koudoku 1.2.4 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -0
- data/app/concerns/koudoku/subscription.rb +15 -17
- data/app/controllers/koudoku/application_controller.rb +0 -1
- data/app/controllers/koudoku/subscriptions_controller.rb +39 -29
- data/app/helpers/koudoku/application_helper.rb +4 -16
- data/app/views/koudoku/subscriptions/_card.html.erb +6 -6
- data/app/views/koudoku/subscriptions/_pricing_table.html.erb +4 -4
- data/app/views/koudoku/subscriptions/_social_proof.html.erb +3 -3
- data/app/views/koudoku/subscriptions/edit.html.erb +3 -3
- data/app/views/koudoku/subscriptions/index.html.erb +1 -1
- data/app/views/koudoku/subscriptions/new.html.erb +1 -1
- data/app/views/koudoku/subscriptions/show.html.erb +9 -9
- data/app/views/koudoku/subscriptions/unauthorized.html.erb +1 -1
- data/config/locales/en.yml +58 -0
- data/config/locales/pt-BR.yml +57 -0
- data/lib/generators/koudoku/templates/app/models/subscription.rb +1 -1
- data/lib/generators/koudoku/templates/config/initializers/koudoku.rb +6 -6
- data/lib/koudoku.rb +23 -15
- data/lib/koudoku/errors.rb +4 -0
- data/lib/koudoku/version.rb +1 -1
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20130318201927_create_customers.rb +1 -1
- data/spec/dummy/db/migrate/20130318204455_create_subscriptions.rb +1 -1
- data/spec/dummy/db/migrate/20130318204458_create_plans.rb +1 -1
- data/spec/dummy/db/migrate/20130318204502_create_coupons.rb +1 -1
- data/spec/dummy/db/migrate/20130520163946_add_interval_to_plan.rb +1 -1
- data/spec/dummy/db/schema.rb +31 -32
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +0 -0
- data/spec/dummy/log/test.log +0 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bdd41d4b7982cbd59644cc114087f962a5d48158
|
4
|
+
data.tar.gz: c4d967213e7fb9e116147eb01a63ecf842546e2a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: debb34bd494f7141f49d8fc6f2814e7ff68bfdc6a32d566ec9d9fd12aab35a96aa8f5eb7b176c14213f973fca6afca1332c378957a09364a630567dd9b6e1b4e
|
7
|
+
data.tar.gz: aec0b3c780f520c04a9154f199ebdcb724e5d38d92fe456c57ec47c8db1f73e99ddfcb9132de5db8fe45eef24b90862ef153ff1f38a6c6d0f31c4a7f712ec3aa
|
data/README.md
CHANGED
@@ -33,6 +33,8 @@ Add the following to `app/views/layouts/application.html.erb` before your `<head
|
|
33
33
|
|
34
34
|
After installing, you'll need to add some subscription plans. (You can see an explanation of each of the attributes in the table below.)
|
35
35
|
|
36
|
+
**Note:** You need to create the plans in your [Stripe Dashboard](https://dashboard.stripe.com) separately.
|
37
|
+
|
36
38
|
```ruby
|
37
39
|
Plan.create({
|
38
40
|
name: 'Personal',
|
@@ -7,7 +7,7 @@ module Koudoku::Subscription
|
|
7
7
|
# client-side after storing the credit card information.
|
8
8
|
attr_accessor :credit_card_token
|
9
9
|
|
10
|
-
belongs_to :plan
|
10
|
+
belongs_to :plan, optional: true
|
11
11
|
|
12
12
|
# update details.
|
13
13
|
before_save :processing!
|
@@ -66,7 +66,7 @@ module Koudoku::Subscription
|
|
66
66
|
prepare_for_upgrade
|
67
67
|
|
68
68
|
begin
|
69
|
-
|
69
|
+
raise Koudoku::NilCardToken, "No card token received. Check for JavaScript errors breaking Stripe.js on the previous page." unless credit_card_token.present?
|
70
70
|
customer_attributes = {
|
71
71
|
description: subscription_owner_description,
|
72
72
|
email: subscription_owner_email,
|
@@ -79,8 +79,8 @@ module Koudoku::Subscription
|
|
79
79
|
customer_attributes[:trial_end] = coupon.free_trial_ends.to_i
|
80
80
|
end
|
81
81
|
end
|
82
|
-
|
83
|
-
customer_attributes[:coupon] = @coupon_code if @coupon_code
|
82
|
+
|
83
|
+
customer_attributes[:coupon] = @coupon_code if @coupon_code
|
84
84
|
|
85
85
|
# create a customer at that package level.
|
86
86
|
customer = Stripe::Customer.create(customer_attributes)
|
@@ -96,7 +96,7 @@ module Koudoku::Subscription
|
|
96
96
|
|
97
97
|
# store the customer id.
|
98
98
|
self.stripe_id = customer.id
|
99
|
-
self.last_four = customer.
|
99
|
+
self.last_four = customer.sources.retrieve(customer.default_source).last4
|
100
100
|
|
101
101
|
finalize_new_subscription!
|
102
102
|
finalize_upgrade!
|
@@ -123,40 +123,38 @@ module Koudoku::Subscription
|
|
123
123
|
|
124
124
|
# fetch the customer.
|
125
125
|
customer = Stripe::Customer.retrieve(self.stripe_id)
|
126
|
-
customer.
|
126
|
+
customer.source = self.credit_card_token
|
127
127
|
customer.save
|
128
128
|
|
129
129
|
# update the last four based on this new card.
|
130
|
-
self.last_four = customer.
|
130
|
+
self.last_four = customer.sources.retrieve(customer.default_source).last4
|
131
131
|
finalize_card_update!
|
132
132
|
|
133
133
|
end
|
134
|
-
|
135
134
|
end
|
136
|
-
|
137
135
|
end
|
138
|
-
|
139
|
-
|
136
|
+
|
137
|
+
|
140
138
|
def describe_difference(plan_to_describe)
|
141
139
|
if plan.nil?
|
142
140
|
if persisted?
|
143
|
-
|
141
|
+
I18n.t('koudoku.plan_difference.upgrade')
|
144
142
|
else
|
145
143
|
if Koudoku.free_trial?
|
146
|
-
|
144
|
+
I18n.t('koudoku.plan_difference.start_trial')
|
147
145
|
else
|
148
|
-
|
146
|
+
I18n.t('koudoku.plan_difference.upgrade')
|
149
147
|
end
|
150
148
|
end
|
151
149
|
else
|
152
150
|
if plan_to_describe.is_upgrade_from?(plan)
|
153
|
-
|
151
|
+
I18n.t('koudoku.plan_difference.upgrade')
|
154
152
|
else
|
155
|
-
|
153
|
+
I18n.t('koudoku.plan_difference.downgrade')
|
156
154
|
end
|
157
155
|
end
|
158
156
|
end
|
159
|
-
|
157
|
+
|
160
158
|
# Set a Stripe coupon code that will be used when a new Stripe customer (a.k.a. Koudoku subscription)
|
161
159
|
# is created
|
162
160
|
def coupon_code=(new_code)
|
@@ -1,12 +1,12 @@
|
|
1
1
|
module Koudoku
|
2
2
|
class SubscriptionsController < ApplicationController
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
before_action :load_owner
|
4
|
+
before_action :show_existing_subscription, only: [:index, :new, :create], unless: :no_owner?
|
5
|
+
before_action :load_subscription, only: [:show, :cancel, :edit, :update]
|
6
|
+
before_action :load_plans, only: [:index, :edit]
|
7
7
|
|
8
8
|
def load_plans
|
9
|
-
@plans = ::Plan.order(:
|
9
|
+
@plans = ::Plan.order(:display_order)
|
10
10
|
end
|
11
11
|
|
12
12
|
def unauthorized
|
@@ -17,13 +17,14 @@ module Koudoku
|
|
17
17
|
def load_owner
|
18
18
|
unless params[:owner_id].nil?
|
19
19
|
if current_owner.present?
|
20
|
-
|
20
|
+
|
21
21
|
# we need to try and look this owner up via the find method so that we're
|
22
22
|
# taking advantage of any override of the find method that would be provided
|
23
23
|
# by older versions of friendly_id. (support for newer versions default behavior
|
24
24
|
# below.)
|
25
|
+
|
25
26
|
searched_owner = current_owner.class.find(params[:owner_id]) rescue nil
|
26
|
-
|
27
|
+
|
27
28
|
# if we couldn't find them that way, check whether there is a new version of
|
28
29
|
# friendly_id in place that we can use to look them up by their slug.
|
29
30
|
# in christoph's words, "why?!" in my words, "warum?!!!"
|
@@ -31,7 +32,7 @@ module Koudoku
|
|
31
32
|
if searched_owner.nil? && current_owner.class.respond_to?(:friendly)
|
32
33
|
searched_owner = current_owner.class.friendly.find(params[:owner_id]) rescue nil
|
33
34
|
end
|
34
|
-
|
35
|
+
|
35
36
|
if current_owner.try(:id) == searched_owner.try(:id)
|
36
37
|
@owner = current_owner
|
37
38
|
else
|
@@ -50,21 +51,32 @@ module Koudoku
|
|
50
51
|
def load_subscription
|
51
52
|
ownership_attribute = :"#{Koudoku.subscriptions_owned_by}_id"
|
52
53
|
@subscription = ::Subscription.where(ownership_attribute => current_owner.id).find_by_id(params[:id])
|
54
|
+
|
55
|
+
# also, if cancan methods are available, we should use that to authorize.
|
56
|
+
if defined?(:can?)
|
57
|
+
return unauthorized unless can? :manage, @subscription
|
58
|
+
end
|
59
|
+
|
53
60
|
return @subscription.present? ? @subscription : unauthorized
|
54
61
|
end
|
55
62
|
|
56
|
-
# the following
|
63
|
+
# the following three methods allow us to show the pricing table before someone has an account.
|
57
64
|
# by default these support devise, but they can be overriden to support others.
|
58
65
|
def current_owner
|
59
66
|
# e.g. "self.current_user"
|
60
67
|
send "current_#{Koudoku.subscriptions_owned_by}"
|
61
68
|
end
|
62
69
|
|
70
|
+
def current_owned_through_or_by
|
71
|
+
# e.g. "self.current_user"
|
72
|
+
send "current_#{Koudoku.subscriptions_owned_through_or_by}"
|
73
|
+
end
|
74
|
+
|
63
75
|
def redirect_to_sign_up
|
64
76
|
# this is a Devise default variable and thus should not change its name
|
65
|
-
# when we change subscription owners from :user to :company
|
66
|
-
session["
|
67
|
-
redirect_to new_registration_path(Koudoku.
|
77
|
+
# when we change subscription owners from :user to :company
|
78
|
+
session["#{Koudoku.subscriptions_owned_through_or_by}_return_to"] = new_subscription_path(plan: params[:plan])
|
79
|
+
redirect_to new_registration_path(Koudoku.subscriptions_owned_through_or_by.to_s)
|
68
80
|
end
|
69
81
|
|
70
82
|
def index
|
@@ -74,9 +86,6 @@ module Koudoku
|
|
74
86
|
redirect_to koudoku.edit_owner_subscription_path(current_owner, current_owner.subscription)
|
75
87
|
end
|
76
88
|
|
77
|
-
# Load all plans.
|
78
|
-
@plans = ::Plan.order(:display_order).all
|
79
|
-
|
80
89
|
# Don't prep a subscription unless a user is authenticated.
|
81
90
|
unless no_owner?
|
82
91
|
# we should also set the owner of the subscription here.
|
@@ -97,9 +106,9 @@ module Koudoku
|
|
97
106
|
else
|
98
107
|
redirect_to_sign_up
|
99
108
|
end
|
100
|
-
|
109
|
+
|
101
110
|
else
|
102
|
-
raise
|
111
|
+
raise I18n.t('koudoku.failure.feature_depends_on_devise')
|
103
112
|
end
|
104
113
|
|
105
114
|
else
|
@@ -115,15 +124,16 @@ module Koudoku
|
|
115
124
|
end
|
116
125
|
|
117
126
|
def create
|
127
|
+
|
118
128
|
@subscription = ::Subscription.new(subscription_params)
|
119
129
|
@subscription.subscription_owner = @owner
|
120
130
|
@subscription.coupon_code = session[:koudoku_coupon_code]
|
121
|
-
|
131
|
+
|
122
132
|
if @subscription.save
|
123
133
|
flash[:notice] = after_new_subscription_message
|
124
|
-
redirect_to after_new_subscription_path
|
134
|
+
redirect_to after_new_subscription_path
|
125
135
|
else
|
126
|
-
flash[:error] = '
|
136
|
+
flash[:error] = I18n.t('koudoku.failure.problem_processing_transaction')
|
127
137
|
render :new
|
128
138
|
end
|
129
139
|
end
|
@@ -132,7 +142,7 @@ module Koudoku
|
|
132
142
|
end
|
133
143
|
|
134
144
|
def cancel
|
135
|
-
flash[:notice] =
|
145
|
+
flash[:notice] = I18n.t('koudoku.confirmations.subscription_cancelled')
|
136
146
|
@subscription.plan_id = nil
|
137
147
|
@subscription.save
|
138
148
|
redirect_to owner_subscription_path(@owner, @subscription)
|
@@ -143,17 +153,17 @@ module Koudoku
|
|
143
153
|
|
144
154
|
def update
|
145
155
|
if @subscription.update_attributes(subscription_params)
|
146
|
-
flash[:notice] =
|
156
|
+
flash[:notice] = I18n.t('koudoku.confirmations.subscription_updated')
|
147
157
|
redirect_to owner_subscription_path(@owner, @subscription)
|
148
158
|
else
|
149
|
-
flash[:error] = '
|
159
|
+
flash[:error] = I18n.t('koudoku.failure.problem_processing_transaction')
|
150
160
|
render :edit
|
151
161
|
end
|
152
162
|
end
|
153
163
|
|
154
164
|
private
|
155
165
|
def subscription_params
|
156
|
-
|
166
|
+
|
157
167
|
# If strong_parameters is around, use that.
|
158
168
|
if defined?(ActionController::StrongParameters)
|
159
169
|
params.require(:subscription).permit(:plan_id, :stripe_id, :current_price, :credit_card_token, :card_type, :last_four)
|
@@ -163,17 +173,17 @@ module Koudoku
|
|
163
173
|
end
|
164
174
|
|
165
175
|
end
|
166
|
-
|
176
|
+
|
167
177
|
def after_new_subscription_path
|
168
178
|
return super(@owner, @subscription) if defined?(super)
|
169
179
|
owner_subscription_path(@owner, @subscription)
|
170
180
|
end
|
171
|
-
|
181
|
+
|
172
182
|
def after_new_subscription_message
|
173
183
|
controller = ::ApplicationController.new
|
174
|
-
controller.respond_to?(:new_subscription_notice_message) ?
|
175
|
-
controller.try(:new_subscription_notice_message) :
|
176
|
-
|
184
|
+
controller.respond_to?(:new_subscription_notice_message) ?
|
185
|
+
controller.try(:new_subscription_notice_message) :
|
186
|
+
I18n.t('koudoku.confirmations.subscription_upgraded')
|
177
187
|
end
|
178
188
|
end
|
179
189
|
end
|
@@ -6,26 +6,14 @@ module Koudoku
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def plan_interval(plan)
|
9
|
-
|
10
|
-
|
11
|
-
"month"
|
12
|
-
when "year"
|
13
|
-
"year"
|
14
|
-
when "week"
|
15
|
-
"week"
|
16
|
-
when "6-month"
|
17
|
-
"half-year"
|
18
|
-
when "3-month"
|
19
|
-
"quarter"
|
20
|
-
else
|
21
|
-
"month"
|
22
|
-
end
|
9
|
+
interval = %w(month year week 6-month 3-month).include?(plan.interval) ? plan.interval.delete('-') : 'month'
|
10
|
+
I18n.t("koudoku.plan_intervals.#{interval}")
|
23
11
|
end
|
24
|
-
|
12
|
+
|
25
13
|
# returns TRUE if the controller belongs to Koudoku
|
26
14
|
# false in all other cases, for convenience when executing filters
|
27
15
|
# in the main application
|
28
|
-
def koudoku_controller?
|
16
|
+
def koudoku_controller?
|
29
17
|
is_a? Koudoku::ApplicationController
|
30
18
|
end
|
31
19
|
end
|
@@ -9,14 +9,14 @@
|
|
9
9
|
<legend><%= title %></legend>
|
10
10
|
|
11
11
|
<div class="control-group">
|
12
|
-
<label class="control-label"
|
12
|
+
<label class="control-label"><%= t('koudoku.payment.card_number') %></label>
|
13
13
|
<div class="controls">
|
14
14
|
<input type="text" size="20" autocomplete="off" class="card-number"/>
|
15
15
|
</div>
|
16
16
|
</div>
|
17
17
|
|
18
18
|
<div class="control-group">
|
19
|
-
<label class="control-label"
|
19
|
+
<label class="control-label"><%= t('koudoku.payment.expiration') %></label>
|
20
20
|
<div class="controls">
|
21
21
|
<input type="text" size="2" class="card-expiry-month input-mini"/>
|
22
22
|
<span> / </span>
|
@@ -25,7 +25,7 @@
|
|
25
25
|
</div>
|
26
26
|
|
27
27
|
<div class="control-group">
|
28
|
-
<label class="control-label"
|
28
|
+
<label class="control-label"><%= t('koudoku.payment.cvc') %></label>
|
29
29
|
<div class="controls">
|
30
30
|
<input type="text" size="4" autocomplete="off" class="card-cvc input-small"/>
|
31
31
|
</div>
|
@@ -39,11 +39,11 @@
|
|
39
39
|
<div class="control-group">
|
40
40
|
<div class="controls">
|
41
41
|
<% if Koudoku.free_trial? %>
|
42
|
-
<button type="submit" class="btn btn-primary submit-button"
|
42
|
+
<button type="submit" class="btn btn-primary submit-button"><%= t('koudoku.payment.save_billing_info') %></button>
|
43
43
|
<% else %>
|
44
|
-
<button type="submit" class="btn btn-primary submit-button"
|
44
|
+
<button type="submit" class="btn btn-primary submit-button"><%= t('koudoku.payment.upgrade_account') %></button>
|
45
45
|
<% end %>
|
46
|
-
<%= link_to
|
46
|
+
<%= link_to t('koudoku.payment.cancel'), owner_subscriptions_path(@owner), class: 'btn' %>
|
47
47
|
</div>
|
48
48
|
</div>
|
49
49
|
|
@@ -7,11 +7,11 @@
|
|
7
7
|
<h4><%= plan_price(plan) %></h4>
|
8
8
|
<div class="call-to-action">
|
9
9
|
<% if @subscription.nil? %>
|
10
|
-
<%= link_to Koudoku.free_trial? ? '
|
10
|
+
<%= link_to Koudoku.free_trial? ? t('koudoku.plan_difference.start_trial') : t('koudoku.subscriptions.sign_up'), koudoku.new_subscription_path(plan: plan.id), class: "btn btn-success btn-large" %>
|
11
11
|
<% elsif @subscription.persisted? %>
|
12
12
|
<% if @subscription.plan == plan %>
|
13
13
|
<%= form_for @subscription, url: owner_subscription_path(@owner, @subscription) do |f| %>
|
14
|
-
<%= f.submit '
|
14
|
+
<%= f.submit t('koudoku.plan_difference.selected'), class: "btn btn-large", disabled: 'disabled' %>
|
15
15
|
<% end %>
|
16
16
|
<% else %>
|
17
17
|
<%= form_for @subscription, url: owner_subscription_path(@owner, @subscription) do |f| %>
|
@@ -20,12 +20,12 @@
|
|
20
20
|
<% end %>
|
21
21
|
<% end %>
|
22
22
|
<% else %>
|
23
|
-
<%= link_to Koudoku.free_trial? ? '
|
23
|
+
<%= link_to Koudoku.free_trial? ? t('koudoku.plan_difference.start_trial') : t('koudoku.plan_difference.upgrade'), new_owner_subscription_path(@owner, plan: plan.id), class: "btn btn-success btn-large" %>
|
24
24
|
<% end %>
|
25
25
|
</div>
|
26
26
|
<ul class="features">
|
27
27
|
<% if Koudoku.free_trial? %>
|
28
|
-
<li class='muted'><%= Koudoku.free_trial_length
|
28
|
+
<li class='muted'><%= t('koudoku.subscriptions.free_trial_for_days', :days => Koudoku.free_trial_length) %></li>
|
29
29
|
<% end %>
|
30
30
|
<%= BlueCloth.new(plan.features.gsub(/\n/, "\n\n")).to_html.gsub(/<(\/?)p>/, '<\1li>').html_safe %>
|
31
31
|
</ul>
|
@@ -1,11 +1,11 @@
|
|
1
1
|
<blockquote>
|
2
|
-
<h4
|
2
|
+
<h4><%= t('koudoku.social_proof.testimonial1.quote') %></h4> — <%= t('koudoku.social_proof.testimonial1.person') %>
|
3
3
|
</blockquote>
|
4
4
|
|
5
5
|
<blockquote>
|
6
|
-
<h4
|
6
|
+
<h4><%= t('koudoku.social_proof.testimonial2.quote') %></h4> — <%= t('koudoku.social_proof.testimonial2.person') %>
|
7
7
|
</blockquote>
|
8
8
|
|
9
9
|
<blockquote>
|
10
|
-
<h4
|
10
|
+
<h4><%= t('koudoku.social_proof.testimonial3.quote') %></h4> — <%= t('koudoku.social_proof.testimonial3.person') %>
|
11
11
|
</blockquote>
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<% if params['update'] == 'card' %>
|
2
|
-
<%= render 'card', title:
|
2
|
+
<%= render 'card', title: t('koudoku.payment.update_payment_information'), url: owner_subscription_path(@owner, @subscription) %>
|
3
3
|
<% else %>
|
4
|
-
<h1
|
4
|
+
<h1><%= t('koudoku.subscriptions.which_plan_is_best') %></h1>
|
5
5
|
<%= render 'pricing_table' %>
|
6
|
-
<p
|
6
|
+
<p><%= t('koudoku.subscriptions.cancel_your_subscription_note_html', :link => (link_to t('koudoku.subscriptions.cancel_your_subscription'), cancel_owner_subscription_path(@owner, @subscription), method: :post)) %></p>
|
7
7
|
<% end %>
|
@@ -1,2 +1,2 @@
|
|
1
|
-
<h1
|
1
|
+
<h1><%= t('koudoku.subscriptions.which_plan_is_best') %></h1>
|
2
2
|
<%= render 'pricing_table' %>
|
@@ -1 +1 @@
|
|
1
|
-
<%= render 'card', title: (Koudoku.free_trial? ?
|
1
|
+
<%= render 'card', title: (Koudoku.free_trial? ? t('koudoku.subscriptions.start_trial') : t('koudoku.subscriptions.upgrade_your_account')), url: owner_subscriptions_path(@owner) %>
|
@@ -1,15 +1,15 @@
|
|
1
1
|
<% if @subscription.plan.present? %>
|
2
|
-
<h2
|
3
|
-
<p
|
4
|
-
<%= link_to '
|
2
|
+
<h2><%= t('koudoku.subscriptions.subscribed') %></h2>
|
3
|
+
<p><%= t('koudoku.subscriptions.subscribed_to_plan', :plan => @subscription.plan.name) %></p>
|
4
|
+
<%= link_to t('koudoku.subscriptions.choose_other_plan'), edit_owner_subscription_path(@owner, @subscription), class: 'btn' %>
|
5
5
|
<% else %>
|
6
|
-
<h2
|
7
|
-
<p
|
8
|
-
<%= link_to '
|
6
|
+
<h2><%= t('koudoku.subscriptions.no_subscription') %></h2>
|
7
|
+
<p><%= t('koudoku.subscriptions.not_subscribed_to_plan') %></p>
|
8
|
+
<%= link_to t('koudoku.subscriptions.choose_plan'), edit_owner_subscription_path(@owner, @subscription), class: 'btn' %>
|
9
9
|
<% end %>
|
10
10
|
|
11
11
|
<br><br>
|
12
12
|
|
13
|
-
<h4
|
14
|
-
<p
|
15
|
-
<%= link_to '
|
13
|
+
<h4><%= t('koudoku.payment.payment_information') %></h4>
|
14
|
+
<p><%= t('koudoku.payment.card_on_file_with_last_four', :last_four => @subscription.last_four) %></p>
|
15
|
+
<%= link_to t('koudoku.payment.update_payment_information'), edit_owner_subscription_path(@owner, @subscription, update: 'card'), class: 'btn' %>
|
@@ -1 +1 @@
|
|
1
|
-
<h1
|
1
|
+
<h1><%= t('koudoku.failure.unauthorized') %></h1>
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# Sample localization file for English. Add more files in this directory for other locales.
|
2
|
+
# See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
|
3
|
+
|
4
|
+
en:
|
5
|
+
koudoku:
|
6
|
+
confirmations:
|
7
|
+
feature_depends_on_devise: "This feature depends on Devise for authentication."
|
8
|
+
subscription_cancelled: "You've successfully cancelled your subscription."
|
9
|
+
subscription_updated: "You've successfully updated your subscription."
|
10
|
+
subscription_upgraded: "You've been successfully upgraded."
|
11
|
+
failure:
|
12
|
+
problem_processing_transaction: "There was a problem processing this transaction."
|
13
|
+
unauthorized: "Unauthorized"
|
14
|
+
plan_intervals:
|
15
|
+
month: "month"
|
16
|
+
year: "year"
|
17
|
+
week: "week"
|
18
|
+
6month: "half-year"
|
19
|
+
3month: "quarter"
|
20
|
+
plan_difference:
|
21
|
+
downgrade: "Downgrade"
|
22
|
+
selected: "Selected"
|
23
|
+
start_trial: "Start Trial"
|
24
|
+
upgrade: "Upgrade"
|
25
|
+
payment:
|
26
|
+
cancel: "Cancel"
|
27
|
+
card_number: "Card Number"
|
28
|
+
card_on_file_with_last_four: "The card on file for your account ends with %{last_four}."
|
29
|
+
cvc: "CVC"
|
30
|
+
expiration: "Expiration (MM/YYYY)"
|
31
|
+
payment_information: "Payment Information"
|
32
|
+
save_billing_info: "Save Billing Information"
|
33
|
+
upgrade_account: "Upgrade Your Account"
|
34
|
+
update_payment_information: "Update Your Payment Information"
|
35
|
+
social_proof:
|
36
|
+
testimonial1:
|
37
|
+
person: "Person at Place"
|
38
|
+
quote: "\"Some Great Quote\""
|
39
|
+
testimonial2:
|
40
|
+
person: "Person at Place"
|
41
|
+
quote: "\"This is a great service and you've been the best ever! Thanks!\""
|
42
|
+
testimonial3:
|
43
|
+
person: "Person at Place"
|
44
|
+
quote: "\"I love you guys and you're the best! You're the best!\""
|
45
|
+
subscriptions:
|
46
|
+
cancel_your_subscription: "cancel your subscription"
|
47
|
+
cancel_your_subscription_note_html: "You can also %{link}."
|
48
|
+
choose_other_plan: "Choose Another Plan"
|
49
|
+
choose_plan: "Choose A Plan"
|
50
|
+
free_trial_for_days: "%{days}-day Free Trial"
|
51
|
+
no_subscription: "No Subscription"
|
52
|
+
not_subscribed_to_plan: "You are not subscribed to a paid plan."
|
53
|
+
sign_up: "Sign up"
|
54
|
+
start_trial: "Start Your Free Trial"
|
55
|
+
subscribed: "You're Subscribed!"
|
56
|
+
subscribed_to_plan: "You're currently subscribed to the %{plan} plan."
|
57
|
+
upgrade_your_account: "Upgrade Your Account"
|
58
|
+
which_plan_is_best: "What Plan Is Best For You?"
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# Translation by Lauro Becker (http://www.organicadigital.com)
|
2
|
+
|
3
|
+
pt-BR:
|
4
|
+
koudoku:
|
5
|
+
confirmations:
|
6
|
+
feature_depends_on_devise: "Esta funcionalidade necessita do Devise para autenticação."
|
7
|
+
subscription_cancelled: "Você cancelou sua subscrição com sucesso."
|
8
|
+
subscription_updated: "Você atualizou sua subscrição com sucesso."
|
9
|
+
subscription_upgraded: "Upgrade feito com sucesso."
|
10
|
+
failure:
|
11
|
+
problem_processing_transaction: "Ocorreu um problema processando a transação."
|
12
|
+
unauthorized: "Não autorizado"
|
13
|
+
plan_intervals:
|
14
|
+
month: "mês"
|
15
|
+
year: "ano"
|
16
|
+
week: "semana"
|
17
|
+
6month: "6 meses"
|
18
|
+
3month: "3 meses"
|
19
|
+
plan_difference:
|
20
|
+
downgrade: "Diminuir"
|
21
|
+
selected: "Selecionado"
|
22
|
+
start_trial: "Iniciar teste"
|
23
|
+
upgrade: "Upgrade"
|
24
|
+
payment:
|
25
|
+
cancel: "Cancelar"
|
26
|
+
card_number: "Número do Cartão"
|
27
|
+
card_on_file_with_last_four: "O cartão de sua conta termina com %{last_four}."
|
28
|
+
cvc: "CVC"
|
29
|
+
expiration: "Expiração (MM/YYYY)"
|
30
|
+
payment_information: "Informações de Pagamento"
|
31
|
+
save_billing_info: "Salvar Informações de Cobrança"
|
32
|
+
upgrade_account: "Upgrade de Sua Conta"
|
33
|
+
update_payment_information: "Atualizar suas Informações de Pagamento"
|
34
|
+
social_proof:
|
35
|
+
testimonial1:
|
36
|
+
person: "Person at Place"
|
37
|
+
quote: "\"Some Great Quote\""
|
38
|
+
testimonial2:
|
39
|
+
person: "Person at Place"
|
40
|
+
quote: "\"This is a great service and you've been the best ever! Thanks!\""
|
41
|
+
testimonial3:
|
42
|
+
person: "Person at Place"
|
43
|
+
quote: "\"I love you guys and you're the best! You're the best!\""
|
44
|
+
subscriptions:
|
45
|
+
cancel_your_subscription: "cancelar sua subscrição"
|
46
|
+
cancel_your_subscription_note_html: "Você também pode %{link}."
|
47
|
+
choose_other_plan: "Escolher Outro Plano"
|
48
|
+
choose_plan: "Escolha Um Plano"
|
49
|
+
free_trial_for_days: "%{days} dias de teste"
|
50
|
+
no_subscription: "Nenhuma Subscrição"
|
51
|
+
not_subscribed_to_plan: "Você não está subscrito em um plano pago."
|
52
|
+
sign_up: "Cadastrar-se"
|
53
|
+
start_trial: "Iniciar seu período de testes"
|
54
|
+
subscribed: "Você está subscrito!"
|
55
|
+
subscribed_to_plan: "Você está atualmente subscrito ao plano %{plan}."
|
56
|
+
upgrade_your_account: "Upgrade de Sua Conta"
|
57
|
+
which_plan_is_best: "Qual é o melhor plano para você?"
|
@@ -2,17 +2,17 @@ Koudoku.setup do |config|
|
|
2
2
|
config.subscriptions_owned_by = :<%= subscription_owner_model %>
|
3
3
|
config.stripe_publishable_key = ENV['STRIPE_PUBLISHABLE_KEY']
|
4
4
|
config.stripe_secret_key = ENV['STRIPE_SECRET_KEY']
|
5
|
-
|
6
|
-
Stripe.api_version = '
|
5
|
+
|
6
|
+
Stripe.api_version = '2017-08-15' # Making sure the API version used is compatible.
|
7
7
|
# config.prorate = false # Default is true, set to false to disable prorating subscriptions
|
8
8
|
# config.free_trial_length = 30
|
9
9
|
|
10
10
|
# Specify layout you want to use for the subscription pages, default is application
|
11
11
|
config.layout = 'application'
|
12
|
-
|
12
|
+
|
13
13
|
# you can subscribe to additional webhooks here
|
14
|
-
# we use stripe_event under the hood and you can subscribe using the
|
15
|
-
# stripe_event syntax on the config object:
|
14
|
+
# we use stripe_event under the hood and you can subscribe using the
|
15
|
+
# stripe_event syntax on the config object:
|
16
16
|
# config.subscribe 'charge.failed', Koudoku::ChargeFailed
|
17
|
-
|
17
|
+
|
18
18
|
end
|
data/lib/koudoku.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "koudoku/engine"
|
2
|
+
require "koudoku/errors"
|
2
3
|
require "generators/koudoku/install_generator"
|
3
4
|
require "generators/koudoku/views_generator"
|
4
5
|
require 'stripe_event'
|
@@ -6,51 +7,58 @@ require 'stripe_event'
|
|
6
7
|
module Koudoku
|
7
8
|
mattr_accessor :subscriptions_owned_by
|
8
9
|
@@subscriptions_owned_by = nil
|
9
|
-
|
10
|
+
|
11
|
+
mattr_accessor :subscriptions_owned_through
|
12
|
+
@@subscriptions_owned_through = nil
|
13
|
+
|
14
|
+
def self.subscriptions_owned_through_or_by
|
15
|
+
@@subscriptions_owned_through || @@subscriptions_owned_by
|
16
|
+
end
|
17
|
+
|
10
18
|
mattr_accessor :stripe_publishable_key
|
11
19
|
@@stripe_publishable_key = nil
|
12
|
-
|
20
|
+
|
13
21
|
mattr_accessor :stripe_secret_key
|
14
22
|
@@stripe_secret_key = nil
|
15
|
-
|
23
|
+
|
16
24
|
mattr_accessor :free_trial_length
|
17
25
|
@@free_trial_length = nil
|
18
26
|
|
19
27
|
mattr_accessor :prorate
|
20
28
|
@@prorate = true
|
21
29
|
|
22
|
-
|
30
|
+
|
23
31
|
@@layout = nil
|
24
|
-
|
32
|
+
|
25
33
|
def self.layout
|
26
34
|
@@layout || 'application'
|
27
35
|
end
|
28
|
-
|
36
|
+
|
29
37
|
def self.layout=(layout)
|
30
38
|
@@layout = layout
|
31
39
|
end
|
32
|
-
|
40
|
+
|
33
41
|
def self.webhooks_api_key=(key)
|
34
42
|
raise "Koudoku no longer uses an API key to secure webhooks, please delete the line from \"config/initializers/koudoku.rb\""
|
35
43
|
end
|
36
|
-
|
44
|
+
|
37
45
|
def self.setup
|
38
46
|
yield self
|
39
|
-
|
47
|
+
|
40
48
|
# Configure the Stripe gem.
|
41
49
|
Stripe.api_key = stripe_secret_key
|
42
50
|
end
|
43
|
-
|
51
|
+
|
44
52
|
# e.g. :users
|
45
53
|
def self.owner_resource
|
46
54
|
subscriptions_owned_by.to_s.pluralize.to_sym
|
47
55
|
end
|
48
|
-
|
56
|
+
|
49
57
|
# e.g. :user_id
|
50
58
|
def self.owner_id_sym
|
51
59
|
:"#{Koudoku.subscriptions_owned_by}_id"
|
52
60
|
end
|
53
|
-
|
61
|
+
|
54
62
|
# e.g. :user=
|
55
63
|
def self.owner_assignment_sym
|
56
64
|
:"#{Koudoku.subscriptions_owned_by}="
|
@@ -60,12 +68,12 @@ module Koudoku
|
|
60
68
|
def self.owner_class
|
61
69
|
Koudoku.subscriptions_owned_by.to_s.classify.constantize
|
62
70
|
end
|
63
|
-
|
71
|
+
|
64
72
|
def self.free_trial?
|
65
73
|
free_trial_length.to_i > 0
|
66
74
|
end
|
67
|
-
|
68
|
-
|
75
|
+
|
76
|
+
|
69
77
|
#
|
70
78
|
# STRIPE_EVENT section
|
71
79
|
#
|
data/lib/koudoku/version.rb
CHANGED
File without changes
|
data/spec/dummy/db/schema.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# encoding: UTF-8
|
2
1
|
# This file is auto-generated from the current state of the database. Instead
|
3
2
|
# of editing this file, please use the migrations feature of Active Record to
|
4
3
|
# incrementally modify your database, and then regenerate this schema definition.
|
@@ -9,45 +8,45 @@
|
|
9
8
|
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
|
10
9
|
# you'll amass, the slower it'll run and the greater likelihood for issues).
|
11
10
|
#
|
12
|
-
# It's strongly recommended
|
11
|
+
# It's strongly recommended that you check this file into your version control system.
|
13
12
|
|
14
|
-
ActiveRecord::Schema.define(:
|
13
|
+
ActiveRecord::Schema.define(version: 20130520163946) do
|
15
14
|
|
16
|
-
create_table "coupons", :
|
17
|
-
t.string
|
18
|
-
t.string
|
19
|
-
t.datetime "created_at",
|
20
|
-
t.datetime "updated_at",
|
15
|
+
create_table "coupons", force: :cascade do |t|
|
16
|
+
t.string "code"
|
17
|
+
t.string "free_trial_length"
|
18
|
+
t.datetime "created_at", null: false
|
19
|
+
t.datetime "updated_at", null: false
|
21
20
|
end
|
22
21
|
|
23
|
-
create_table "customers", :
|
24
|
-
t.string
|
25
|
-
t.datetime "created_at", :
|
26
|
-
t.datetime "updated_at", :
|
22
|
+
create_table "customers", force: :cascade do |t|
|
23
|
+
t.string "email"
|
24
|
+
t.datetime "created_at", null: false
|
25
|
+
t.datetime "updated_at", null: false
|
27
26
|
end
|
28
27
|
|
29
|
-
create_table "plans", :
|
30
|
-
t.string
|
31
|
-
t.string
|
32
|
-
t.float
|
33
|
-
t.text
|
34
|
-
t.boolean
|
35
|
-
t.integer
|
36
|
-
t.datetime "created_at",
|
37
|
-
t.datetime "updated_at",
|
38
|
-
t.string
|
28
|
+
create_table "plans", force: :cascade do |t|
|
29
|
+
t.string "name"
|
30
|
+
t.string "stripe_id"
|
31
|
+
t.float "price"
|
32
|
+
t.text "features"
|
33
|
+
t.boolean "highlight"
|
34
|
+
t.integer "display_order"
|
35
|
+
t.datetime "created_at", null: false
|
36
|
+
t.datetime "updated_at", null: false
|
37
|
+
t.string "interval"
|
39
38
|
end
|
40
39
|
|
41
|
-
create_table "subscriptions", :
|
42
|
-
t.string
|
43
|
-
t.integer
|
44
|
-
t.string
|
45
|
-
t.integer
|
46
|
-
t.string
|
47
|
-
t.float
|
48
|
-
t.integer
|
49
|
-
t.datetime "created_at",
|
50
|
-
t.datetime "updated_at",
|
40
|
+
create_table "subscriptions", force: :cascade do |t|
|
41
|
+
t.string "stripe_id"
|
42
|
+
t.integer "plan_id"
|
43
|
+
t.string "last_four"
|
44
|
+
t.integer "coupon_id"
|
45
|
+
t.string "card_type"
|
46
|
+
t.float "current_price"
|
47
|
+
t.integer "customer_id"
|
48
|
+
t.datetime "created_at", null: false
|
49
|
+
t.datetime "updated_at", null: false
|
51
50
|
end
|
52
51
|
|
53
52
|
end
|
data/spec/dummy/db/test.sqlite3
CHANGED
File without changes
|
File without changes
|
data/spec/dummy/log/test.log
CHANGED
File without changes
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: koudoku
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Culver
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-11-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -181,6 +181,8 @@ files:
|
|
181
181
|
- app/views/layouts/koudoku/application.html.erb
|
182
182
|
- config/environment.rb
|
183
183
|
- config/initializers/stripe_event.rb
|
184
|
+
- config/locales/en.yml
|
185
|
+
- config/locales/pt-BR.yml
|
184
186
|
- config/routes.rb
|
185
187
|
- lib/generators/koudoku/install_generator.rb
|
186
188
|
- lib/generators/koudoku/templates/app/models/coupon.rb
|
@@ -190,6 +192,7 @@ files:
|
|
190
192
|
- lib/generators/koudoku/views_generator.rb
|
191
193
|
- lib/koudoku.rb
|
192
194
|
- lib/koudoku/engine.rb
|
195
|
+
- lib/koudoku/errors.rb
|
193
196
|
- lib/koudoku/version.rb
|
194
197
|
- lib/tasks/koudoku_tasks.rake
|
195
198
|
- spec/concerns/koudoku/plan_spec.rb
|
@@ -271,7 +274,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
271
274
|
version: '0'
|
272
275
|
requirements: []
|
273
276
|
rubyforge_project:
|
274
|
-
rubygems_version: 2.
|
277
|
+
rubygems_version: 2.6.8
|
275
278
|
signing_key:
|
276
279
|
specification_version: 4
|
277
280
|
summary: Robust subscription support for Rails with Stripe.
|