Giter Site home page Giter Site logo

payola's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

payola's Issues

Subscriptions

Is there potential to have this be a one-stop solution for accepting a card for subscriptions too?

  • webhook modification for handling subscriptions
  • subscription cancelations
  • up/down-grade plans (in-progress - Pete #42)
  • update cards
  • multiple subscriptions (?)
  • subscription coupon (should be very similar to Payola::Sale)
  • subscription affiliate (should be very similar to Payola::Sale) (in-progress - Jeremy)
  • metered billing / one time add-on payments (?)
  • per user pricing ability (?)
  • documentation!
  • generators to place payola partials in the main app

Handle invalid cards when creating new subscriptions

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.

Subscription start time

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:

  • Payola + Devise
  • The CC info is good, Payola creates and starts the subscription
  • The password + password_confirmation do not match
  • Instead of correcting the error and finishing account creation, the user decides to bail
  • Now the user is paying for a subscription that they can not access because their account was not created

Something similar could happen with any method of creating accounts or other supporting records that depend on subscriptions.

Possible solutions:

  • Messaging - Somehow tell the user that their subscription has been activated even though there was a problem creating their account.
  • Add a callback - Instead of starting the subscription automatically we could instruct developers to add a call to @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?

improve README

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 URL
  • name (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

Trouble with heroku rails console + Payola

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

Turbolinks

Hello,

I was just wondering if support for turbolinks will be added in the future?

Thanks,

Drew

PayolaOnestepSubscriptionForm errorHandler

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);
        };

Consolidate and DRY up Javascript

Essentially the same javascript is repeated in four different files with very minor changes. Find some common ground and DRY that up.

formatted_price

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

Rails Beta 4.2.0

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)

Can't mount to folder other than /payola

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.

Offer a synchronous mode

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.

Allow custom form fields with checkout button

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.

Custom Forms

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.

Payment Details - Description

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?

Where to put Stripe keys?

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...

Handle partial refunds

Right now Payola assumes refunds are an all-or-nothing thing. There needs to be a facility for handling partial refunds.

Subscriptions broken w/latest Stripe gem

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.

undefined method `formatted_price'

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">

Coupon code getting lost

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:
Image of Form

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"}

Clarify docs for one time payments

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?

Preserve `stripe_customer_id` for subsequent subscriptions

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.

Feature request: Subscription quantities

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.

Upgrades

Add a way to change a product (within the same class) and charge the difference to the customer's card.

  • look up sale
  • look up new product
  • calculate amount
  • generate a new sale for the new product at upgrade price
  • charge the customer's saved card for that amount
  • send a notification with old and new sale to application to allow it to swizzle whatever it needs
  • need some JS and a background worker for this

Documentation Design

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.

  • Configuration options
  • One-time payments
  • Subscriptions

PriceHelper hardcodes price to $

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

One step subscription form error handling

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.

ActiveModel Support

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!

`stripe-rails` gem dependency

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?

Associations

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?

Explore using Invoices for one-time charges

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:

  • A 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::InvoiceItems. 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 charge
  • Payola::ChargeCard would create a Stripe::Invoice and pay it, instead of directly creating a Stripe::Charge
  • Receipts would need to handle invoice items.
  • Probably lots of other stuff.

<%= Payola.publishable_key %> returns the lambda.to_s

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("#&lt;Proc:0x0000010c2e01c8@/Users/jgreen/.rvm/gems/ruby-2.1.5/gems/payola-payments-1.2.3/lib/payola.rb:78 (lambda)&gt;");

It seems to be related to this commit : e739e167

Payola::VERSION uninitialized constant breaks gem

/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."

Customer-controlled amounts

Allow a customer to control the amount of a product. For example, this is useful for donations.

  • Ability to mark a product as having a variable amount
  • Teach javascript about user-supplied amount
  • CreateSale needs to know about the amount (pull it off of params) and verify that the product can have a variable amount.
  • Have a method that lets the product define if the given amount is in the correct range and call that method from CreateSale.

release for 1.2.5?

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!

Allow in-line processing

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?

Stripe::AuthenticationError in Payola::SubscriptionsController#destroy

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."

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.