koudoku 1.2.4 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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.
|