payolapayments / payola Goto Github PK
View Code? Open in Web Editor NEWDrop-in Rails engine for accepting payments with Stripe
Home Page: http://www.payola.io
License: Other
Drop-in Rails engine for accepting payments with Stripe
Home Page: http://www.payola.io
License: Other
If you load all of the JS at the end of the page the PayolaCheckout
is of course not going to be defined. The chunk of code in the JS needs to be at the end of the page after the JS loads, not inline with the form.
Is there potential to have this be a one-stop solution for accepting a card for subscriptions too?
Payola::Sale
)Payola::Sale
) (in-progress - Jeremy)Now that a subscription inherits the customer from previous subscriptions (see #57) there exists the possibility that creating a subscription will result in a Stripe::InvalidRequestError
because their card is no longer valid, or was deleted or something.
Gracefully handle this by propagating the error up to the JS and throwing some sort of event that the application can catch to redirect to a page with a payment form.
Also Payola::CreateSubscription
needs to do the right thing if it's given a token for a customer with an existing subscription. Namely, assign the card to the existing customer.
I've been working on integrating Payola subscriptions into my project and I've realized that the current implementation around starting subscriptions automatically makes it possible for things to land in a state that they user would not expect. That state being that their subscription is active and their card is being charged, but their account has not been created. Imagine this scenario:
Something similar could happen with any method of creating accounts or other supporting records that depend on subscriptions.
Possible solutions:
@subscription.start
once any application specific setup has been done.I'm leaning towards the callback because it puts the problem/solution on the dev that's integrating Payola, instead of on the end user to understand the state of the system in the background.
Thoughts?
It would be nice if Payola Subscriptions could have a tax_percent
as supported by Stripe: https://stripe.com/docs/api#create_subscription
When selling software subscriptions in EU, you need to be able to apply different VAT rates depending on what country the customer is from. At the moment there is no way to do this with Payola, right?
I got stuck on the README section "Single Sales". I think it would help if you add:
You'll need a model for each product you sell. You'll add Payola::Sellable
to the model after you create it. Each sellable model requires three attributes:
price
(integer), an amount in the format that Stripe expects. For USD this is cents.permalink
, (string), a human-readable slug that is exposed in the URLname
(string), a human-readable name exposed on product pages(Should price be a string or an integer? The README isn't clear.)
(add the but about optional methods here)
For example, to create a 'Book' model:
$ rails g model Book price:integer permalink:string name:string
$ rake db:migrate
Modify the Book model:
class Book < ActiveRecord::Base
include Payola::Sellable
end
Finally, add a book to the database:
$ rails console
$ blah blah
With payola included in my project I'm unable to run a rails console at heroku. Serving the site at heroku works just fine. Here's the stack trace:
$ heroku run rails c --app remarq-staging
Running `rails c` attached to terminal... up, run.3138
/app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:478:in `load_missing_constant': Circular dependency detected while autoloading constant ApplicationController (RuntimeError)
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:180:in `const_missing'
from /app/vendor/bundle/ruby/2.1.0/gems/payola-payments-1.2.2/lib/payola/engine.rb:23:in `block (2 levels) in <class:Engine>'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/lazy_load_hooks.rb:38:in `instance_eval'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/lazy_load_hooks.rb:38:in `execute_hook'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/lazy_load_hooks.rb:45:in `block in run_load_hooks'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/lazy_load_hooks.rb:44:in `each'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/lazy_load_hooks.rb:44:in `run_load_hooks'
from /app/vendor/bundle/ruby/2.1.0/gems/actionpack-4.1.7/lib/action_controller/base.rb:265:in `<class:Base>'
from /app/vendor/bundle/ruby/2.1.0/gems/actionpack-4.1.7/lib/action_controller/base.rb:164:in `<module:ActionController>'
from /app/vendor/bundle/ruby/2.1.0/gems/actionpack-4.1.7/lib/action_controller/base.rb:5:in `<top (required)>'
from /app/app/controllers/application_controller.rb:1:in `<top (required)>'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:247:in `require'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:247:in `block in require'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:232:in `load_dependency'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:247:in `require'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:348:in `require_or_load'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:480:in `load_missing_constant'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:180:in `const_missing'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/inflector/methods.rb:238:in `const_get'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/inflector/methods.rb:238:in `block in constantize'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/inflector/methods.rb:236:in `each'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/inflector/methods.rb:236:in `inject'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/inflector/methods.rb:236:in `constantize'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/core_ext/string/inflections.rb:66:in `constantize'
from /app/vendor/bundle/ruby/2.1.0/gems/devise-3.2.4/app/controllers/devise_controller.rb:2:in `<top (required)>'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:247:in `require'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:247:in `block in require'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:232:in `load_dependency'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:247:in `require'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:348:in `require_or_load'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:480:in `load_missing_constant'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:180:in `const_missing'
from /app/vendor/bundle/ruby/2.1.0/gems/devise-3.2.4/app/controllers/devise/confirmations_controller.rb:1:in `<top (required)>'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:247:in `require'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:247:in `block in require'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:232:in `load_dependency'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:247:in `require'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:348:in `require_or_load'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:307:in `depend_on'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:225:in `require_dependency'
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.1.7/lib/rails/engine.rb:468:in `block (2 levels) in eager_load!'
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.1.7/lib/rails/engine.rb:467:in `each'
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.1.7/lib/rails/engine.rb:467:in `block in eager_load!'
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.1.7/lib/rails/engine.rb:465:in `each'
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.1.7/lib/rails/engine.rb:465:in `eager_load!'
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.1.7/lib/rails/engine.rb:346:in `eager_load!'
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.1.7/lib/rails/application/finisher.rb:58:in `each'
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.1.7/lib/rails/application/finisher.rb:58:in `block in <module:Finisher>'
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.1.7/lib/rails/initializable.rb:30:in `instance_exec'
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.1.7/lib/rails/initializable.rb:30:in `run'
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.1.7/lib/rails/initializable.rb:55:in `block in run_initializers'
from /app/vendor/ruby-2.1.5/lib/ruby/2.1.0/tsort.rb:226:in `block in tsort_each'
from /app/vendor/ruby-2.1.5/lib/ruby/2.1.0/tsort.rb:348:in `block (2 levels) in each_strongly_connected_component'
from /app/vendor/ruby-2.1.5/lib/ruby/2.1.0/tsort.rb:427:in `each_strongly_connected_component_from'
from /app/vendor/ruby-2.1.5/lib/ruby/2.1.0/tsort.rb:347:in `block in each_strongly_connected_component'
from /app/vendor/ruby-2.1.5/lib/ruby/2.1.0/tsort.rb:345:in `each'
from /app/vendor/ruby-2.1.5/lib/ruby/2.1.0/tsort.rb:345:in `call'
from /app/vendor/ruby-2.1.5/lib/ruby/2.1.0/tsort.rb:345:in `each_strongly_connected_component'
from /app/vendor/ruby-2.1.5/lib/ruby/2.1.0/tsort.rb:224:in `tsort_each'
from /app/vendor/ruby-2.1.5/lib/ruby/2.1.0/tsort.rb:205:in `tsort_each'
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.1.7/lib/rails/initializable.rb:54:in `run_initializers'
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.1.7/lib/rails/application.rb:300:in `initialize!'
from /app/config/environment.rb:5:in `<top (required)>'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:247:in `require'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:247:in `block in require'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:232:in `load_dependency'
from /app/vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.7/lib/active_support/dependencies.rb:247:in `require'
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.1.7/lib/rails/application.rb:276:in `require_environment!'
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.1.7/lib/rails/commands/commands_tasks.rb:147:in `require_application_and_environment!'
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.1.7/lib/rails/commands/commands_tasks.rb:68:in `console'
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.1.7/lib/rails/commands/commands_tasks.rb:40:in `run_command!'
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.1.7/lib/rails/commands.rb:17:in `<top (required)>'
from /app/bin/rails:8:in `require'
from /app/bin/rails:8:in `<main>'
I completely removed payola from my project and then was able to run a console at heroku. Then, just to make sure, I only added payola back to the Gemfile, but didn't re-enable any of my integration bits. After a push to heroku I was back to getting the same error instead of a working console.
The message seems to say that it's having trouble with ApplicationController
, but it's pretty normal.
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
def require_admin_user
if !user_signed_in? || !current_user.admin
redirect_to root_path
end
end
def after_sign_in_path_for(resource)
request.env['omniauth.origin'] || stored_location_for(resource) || reports_path
end
def after_sign_up_path_for(resource)
request.env['omniauth.origin'] || stored_location_for(resource) || reports_path
end
end
Hello,
I was just wondering if support for turbolinks will be added in the future?
Thanks,
Drew
Currently looks like this:
var errorHandler = function(jqXHR){
if(jqXHR.responseJSON.status === "errored"){
PayolaSubscriptionForm.showError(form, jqXHR.responseJSON.error);
}
};
Should be:
var errorHandler = function(jqXHR){
PayolaOnestepSubscriptionForm.showError(form, jqXHR.responseJSON.error);
};
Essentially the same javascript is repeated in four different files with very minor changes. Find some common ground and DRY that up.
Hi Pete, nice work on this gem.
I'm running into this error a lot -
"undefined method `formatted_price' for "
Hope you can help me out...
Rich
When I bundle installed, I get this error...
Bundler could not find compatible versions for gem "rails":
In Gemfile:
payola-payments (>= 0) ruby depends on
rails (~> 4.1.4) ruby
rails (4.2.0.beta2)
I tried to mount payola to /subdir/payola, however the javascript paths have "/payola/buy" etc hard-coded into them, so you're forced to mount it to the root directly.
My use case is that I have a third-party hosted microsite on which I want to put a Stripe Checkout button. It would be easy enough to drop Payola into my existing Rails app to process the payment and redirect back to the microsite, but the asynchronous nature doesn't allow it (needs the payola JS running on the page to check the transaction status).
But if a wait for the user is tolerable (as in my case), it'd be nice to just do the transaction synchronously and redirect to the redirect_url
after create_object
rather than rendering the status as JSON.
Right now there's no way to add fields to the checkout button. For example, if you want to collect a name or address or something there's no way to pass that. This should be something like the custom form task, where charge_verifier
gets the params hash or something.
Payola should have an easy way to hook up a custom form with the javascript for the async actions. How do we pass custom form information down into the action, though? Maybe charge_verifier
gets the params that were POSTed that Payola doesn't care about, stripping out stripeToken
, for example.
I must be just not seeing this in the documentation, but can't find anywhere how to set the description that appears in the Stripe Invoice itself. Currently it's a short random string, but would definitely need to have the invoice name there for production use.
I know it's updatable from the Stripe website, but that's not ideal at all. Could someone kindly point this out to me, please?
I've tried setting up an initializer/stripe.rb containing the following
Rails.configuration.stripe = {
:publishable_key => ENV['PUBLISHABLE_KEY'],
:secret_key => ENV['SECRET_KEY']
}
Stripe.api_key = Rails.configuration.stripe[:secret_key]
I've put test keys into figaro's application.yml, rebooted and still get the js alert of "Stripe Checkout is missing the required 'key'".
Viewing the page source shows the following missing the key within "publishable_key: """
<script type="text/javascript">
Payola.setUpStripeCheckoutButton({
form_id: "payola-button-product-shirt-form",
button_id: "payola-button-product-shirt",
error_div_id: "payola-button-product-shirt-errors",
product_class: "product",
product_permalink: "shirt",
price: 10,
name: "awesome t-shirt",
description: "awesome t-shirt ($0.10)",
product_image_path: "",
publishable_key: "",
panel_label: "",
allow_remember_me: true,
email: "",
verify_zip_code: false
});
</script>
Where do you place the stripe keys when using Payola? w/out buying the book you link to...
If you raise an exception in charge_verifier
, the error will be passed back but the submit button will stay disabled.
Right now Payola assumes refunds are an all-or-nothing thing. There needs to be a facility for handling partial refunds.
It's possible to walk the list of plan IDs and find one that's cheaper than what you're offered. Add a guid field on the plan and use it instead of the numeric ID.
When using Payola with the latest version of the stripe gem (1.20.1
), the StartSubscription.run
method throws the following exception:
NoMethodError: undefined method 'cards' for #<Stripe::Customer:...>
The offending code is on line 30 of the StartSubscription
class.
It seems at some point Stripe removed the Stripe::Customer#cards
method and replaced it with Stripe::Customer::#sources
. Changing the offending line to call the #sources
method instead seems to fix things for me for me, but I haven't had a chance to run the full test suite to ensure that it doesn't break something else.
I've attempted to set up an application with Payola. When I visit the page that contains:
<%= render 'payola/transactions/checkout', sellable: Book.first %>
I get the error:
Started GET "/" for 127.0.0.1 at 2014-11-11 11:30:52 -0800
ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations".* FROM "schema_migrations"
Processing by VisitorsController#index as HTML
Book Load (0.2ms) SELECT "books".* FROM "books" ORDER BY "books"."id" ASC LIMIT 1
Rendered /Users/danielkehoe/.rvm/gems/ruby-2.1.3@rails-bootstrap_com/gems/payola-payments-1.1.4/app/views/payola/transactions/_checkout.html.erb (22.4ms)
Rendered visitors/index.html.erb within layouts/application (47.5ms)
Completed 500 Internal Server Error in 103ms
NoMethodError - undefined method `formatted_price' for #<#<Class:0x007ff085022ce0>:0x007ff0850a19a0>:
payola-payments (1.1.4) app/views/payola/transactions/_checkout.html.erb:5:in `___sers_danielkehoe__rvm_gems_ruby_______rails_bootstrap_com_gems_payola_payments_______app_views_payola_transactions__checkout_html_erb__3259970943117620536_70335492291020'
.
.
.
My migration for the Book model looks like this:
class CreateBooks < ActiveRecord::Migration
def change
create_table :books do |t|
t.integer :price
t.string :permalink
t.string :name
t.timestamps null: false
end
end
end
(I tried price
as a string and as an integer and got the same failure.)
My Book model:
class Book < ActiveRecord::Base
include Payola::Sellable
end
And the actual Book object:
$ rails console
Loading development environment (Rails 4.2.0.beta4)
>> b = Book.first
Book Load (0.2ms) SELECT "books".* FROM "books" ORDER BY "books"."id" ASC LIMIT 1
=> #<Book id: 1, price: 99500, permalink: "book", name: "Rails Bootstrap", created_at: "2014-11-11 19:30:43", updated_at: "2014-11-11 19:30:43">
Gemfile: gem 'payola-payments', git: 'https://github.com/peterkeen/payola'
I'm using the following form:
<div class="row">
<div class="col-md-3 col-md-offset-4">
<div class="well">
<%= form_tag("/subscribe/#{@plan.id}",
role: 'form',
class: 'payola-onestep-subscription-form',
'data-payola-base-path' => '/payola',
'data-payola-error-selector' => '.payola-error',
'data-payola-plan-type' => @plan.plan_class,
'data-payola-plan-id' => @plan.id) do %>
<div class="form-group">
<label>Email Address</label>
<input type="email"
name="email"
data-payola="email"
placeholder="[email protected]"
class="form-control"
value="<%= current_user.email %>"
readonly></input>
</div>
<div class="form-group">
<label>Card number</label>
<input type="text"
size="20"
data-stripe="number"
class="card-number form-control"
placeholder="**** **** **** ****"></input>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>Exp</label>
<input type="text"
size="8"
class="exp-date form-control"
placeholder="MM / YY"></input>
<input type="hidden" data-stripe="exp_month"></input>
<input type="hidden" data-stripe="exp_year"></input>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label>CVC</label>
<input type="text"
size="4"
data-stripe="cvc"
class="form-control"
placeholder="***"></input>
</div>
</div>
</div>
<div class="form-group">
<label>Promo Code</label>
<input type="text"
name="coupon"
size="20"
data-stripe="coupon"
class="form-control"
placeholder="code"></input>
</div>
<div class="text-center">
<input type="submit" value="Subscribe" class="btn btn-info btn-lg btn-block"></input>
</div>
<% end %>
</div>
</div>
</div>
Here is the form before submit:
Here is what I'm seeing in my log:
Processing by SubscribeController#create as */*
Parameters: {"utf8"=>"โ", "authenticity_token"=>"dIaCPWDJaBq0m/rqxiFSfLLNILcLtdhaQ4D6nAYLe3p6bbX2d/O6DPQ1BEo0T3+9VY431IbaI1sDdpRN3quLDQ==", "email"=>"[email protected]", "coupon"=>"", "plan_type"=>"subscription_plan", "plan_id"=>"4", "stripeToken"=>"tok_15Oh9BIxHSxj5NYxOOjpClL0", "stripeEmail"=>"[email protected]", "quantity"=>"", "id"=>"4"}
The wiki page for one time payments shows:
<%= form_for @whatever,
html: {
class: 'payola-payment-form',
'data-payola-base-path' => main_app.payola_path,
'data-payola-product' => @product.product_class,
'data-payola-permalink' => @product.permalink
} do |f| %>
Could you please offer an example for the values main_app.payola_path
, @product.product_class
, and @product.permalink
.
If my application is named RailsStripe
should I have:
'data-payola-base-path' => RailsStripe.payola_path
?
If I have a class named Product
for my product, and my controller new
action includes @product = Product.first
and it has attributes name
and permalink
do I use:
'data-payola-product' => @product.class
?
https://stripe.com/docs/upgrades
card
and default_card
are gone, replaced by source
and default_source
.
We should probably add a way to peg an API version. That way we don't have to worry about this kind of thing immediately.
Right now Payola creates a brand new customer every time someone subscribes, even if they've been a customer before. Instead, we should try to preserve the stripe_customer_id
across re-subscriptions.
Logic:
If the owner is present AND the owner has a previous subscription, copy the stripe_customer_id
forward. If we have been given a token, replace the card info with the new card, otherwise attempt to use the existing card.
Just putting these requests here as I come across the need. Stripe has added quantities to their subscriptions now, which allow per-user subscriptions. AKA if I have a $30/user/month plan, then I can have a $30/month subscription, and pass a quantity of 5, which would mean that user has a $150/month total pricing under the $30/user/month tier. Couldn't find this listed as a passable attribute to Payola's subscriptions in the docs, maybe it's there and I missed it.
Add a way to change a product (within the same class) and charge the difference to the customer's card.
Right now all of the documentation is slammed into the README, which makes the README super long and hard to navigate. We should split the docs into sections, all with their own wiki page.
At the moment the payment subtitle is (name - price), but the price is always formatted in USD even when the current is set to e.g. GBP
I've worked around this by monkeypatching PriceHelper to be hardcoded to GBP (which is fine for me), but it would be great if it was smart enough to figure it out from the object's currency
https://github.com/peterkeen/payola/blob/master/app/services/payola/start_subscription.rb#L58
Customer never gets created when there are > 1 subscriptions with no stripe_customer_id. E.g. I had 2 pending. Deleting all subscriptions via the console fixed it.
I've been trying to keep up with the recent changes to subscription forms so bare with me if this has since changed. But I'm having an issue when trying to create a subscription with an invalid credit card. The issue is rooted in that when there's an error, a 400
response is returned to the poller who is checking the status of the subscription. Because this is an error, jQuery stops processing the AJAX request (it seems) so data.status
is never able to be checked. The end result is essentially a noopt
on the poller.
One solution to this would be to always return a 200
and use codes/statuses within the response data to determine success/failure. This looks like the intent in subscription_form_onestep.js
even though the controller is returning a 400
.
An alternate short circuit would be to attach an error handler to the request and return a general "Could not process payment" error:
// app/assets/javascripts/payola/subscription_form_onestep.js
$.get(base_path + '/subscription_status/' + guid, function(data) {
if (data.status === "active") {
window.location = base_path + '/confirm_subscription/' + guid;
} else if (data.status === "errored") {
PayolaOnestepSubscriptionForm.showError(form, data.error);
} else {
setTimeout(function() { PayolaOnestepSubscriptionForm.poll(form, num_retries_left - 1, guid, base_path); }, 500);
}
}).
error(function() {
PayolaOnestepSubscriptionForm.showError(form, "There was a problem processing your payment.");
});
Are there any thoughts on which is a preferable direction to take this? That is, assuming this hasn't be resolved already.
Thanks in advance.
Currently the installer looks for //= require_tree .
in application.js
and apparently sometimes this is missing. The current culprit is Rails Composer, but it's hard to say. In any case, we should just include it after jquery
.
Do you have any plans or possibly have already started an ActiveModel branch? If not, would you be interested? I would be happy to fork and work on such a feature to use this gem with a mongoid back-end if so, I'd probably need to refactor and rearrange some things around to accommodate though.
Let me know and thanks for sharing!
In order to get the one step subscription form's javascript working as expected, I had to install and configure stripe-rails
by adding stripe keys to the application configuration:
config.stripe.secret_key = Figaro.env.stripe_secret_key
config.stripe.publishable_key = Figaro.env.stripe_publishable_key
And including the stripe-rails
partial:
<%= render partial: "stripe/js" %>
I didn't see this in the documentation anywhere which leads me to ask: Am I doing something wrong?
Goals: 4.0 and 100% coverage.
Please correct me if I'm mistaken but wouldn't this create a new customer if the owner in question has exactly 1 subscription?
https://github.com/peterkeen/payola/blob/master/app/services/payola/start_subscription.rb#L58
NoMethodError: undefined method `plan' for #<Payola::Subscription:0x007fc47c5a4d10>
from /Users/krainboltgreene/.rvm/gems/ruby-2.1.5@sketchymicro-app/gems/activemodel-4.2.0/lib/active_model/attribute_methods.rb:433:in `method_missing'
What do you think is the best way to handle associations between a Payola::Sale and User?
Right now I'm doing this:
class User < ActiveRecord::Base
has_many :sales, primary_key: :email, foreign_key: :email, class_name: "Payola::Sale"
end
Payola::Sale.class_eval do
has_one :user, primary_key: :email, foreign_key: :email
end
And that works, but I think there needs to be a lot better method of handling it. Any thoughts?
From the announcement:
Payola has built-in support for Sidekiq and Sucker Punch, but it's easy to add new backend worker systems which makes it even easier to adapt to your current system.
ActiveJob support would let anyone use any queue: https://github.com/rails/rails/tree/master/activejob
You can create an invoice manually, which means you can group multiple "things" into a charge. For example, if you need to charge sales tax you could calculate it and add it onto the invoice as an invoice item in charge_verifier
, or perhaps some other hook. Or, if you have a shopping cart you could add all of the items in the cart to an invoice as invoice items.
Things that this would impact:
Payola::Sellable
can implement an invoice_items
, which would return a list of things that act like Payola::Sellable
(i.e. have a name, description, price). These items would get added as Stripe::InvoiceItem
s. Need to figure out a way to handle this in terms of the Checkout partial.Payola::Sale
would need to point at an invoice instead of / in addition to a chargePayola::ChargeCard
would create a Stripe::Invoice
and pay it, instead of directly creating a Stripe::Charge
I just updated to 1.2.3 and all of a sudden none of the payola JS works. I finally tracked it down to the call to setPublishableKey
. It looks like this in the source:
Stripe.setPublishableKey("#<Proc:0x0000010c2e01c8@/Users/jgreen/.rvm/gems/ruby-2.1.5/gems/payola-payments-1.2.3/lib/payola.rb:78 (lambda)>");
It seems to be related to this commit : e739e167
/home/funkdified/.rvm/gems/[email protected]/bundler/gems/payola-0a1c2b312b4f/lib/payola/engine.rb:41:in `block in <class:Engine>': uninitialized constant Payola::VERSION (NameError)
for now I've just commented out
Rails.logger.info "Payola v#{Payola::VERSION}. See LICENSE and the LGPL-3.0 for licensing details."
Allow a customer to control the amount of a product. For example, this is useful for donations.
CreateSale
needs to know about the amount (pull it off of params) and verify that the product can have a variable amount.CreateSale
.I've seen the post on @peterkeen's site about using Stripe Checkout for Subscriptions, can we integrate that into Payola? Would make for a very clean plug-and-play subscription gem.
Hey Pete, sorry to bug you with this, but I was wondering if you could release 1.2.5 sometime soon so I can get the updated subscription creation handling deployed. Thanks!
This is something I've talked to a few other developers about in passing, and I think for usability's sake, it might make sense to at least allow for in-line processing of purchases and subscriptions. Personally, I would prefer inline. Especially, if not solely, for subscriptions.
There are very few sites that I can think of that would ever be riddled with bottlenecked web servers due to hogging by subscription processes. This is something that most users will do one time. For most subscription based services, they rarely change their plans, or they do so very sparingly. I would rather have immediate feedback than have to deal with any async issues that could arise. Thoughts on allowing this?
When I try to cancel an account using the built in helper button I'm getting Stripe::AuthenticationError in Payola::SubscriptionsController#destroy
.
The source of the error is the Payola::CancelSubscription
service. I've tried adding the secret_key
into the call to delete
, with no luck, like so:
customer.subscriptions.retrieve(subscription.stripe_id,secret_key).delete(secret_key)
I have found that adding this:
Stripe.api_key = secret_key
before the call to delete will fix the problem. Not sure if we're specifically avoiding doing that.
The Stripe documentation makes it sound like this may be a bug in the Stripe Ruby lib.
https://stripe.com/docs/api/ruby#authentication
"...or you can always pass a key directly to an object's constructor. Authentication is transparently handled for you in subsequent method calls."
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.