saucy 0.2.28.1 → 0.2.29
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.
- data/app/mailers/billing_mailer.rb +9 -0
- data/app/mailers/invitation_mailer.rb +11 -0
- data/app/views/billing_mailer/expiring_trial.text.erb +19 -0
- data/config/locales/en.yml +1 -0
- data/lib/generators/saucy/features/templates/features/trial_plans.feature +10 -0
- data/lib/generators/saucy/features/templates/step_definitions/account_steps.rb +6 -0
- data/lib/generators/saucy/features/templates/step_definitions/cron_steps.rb +4 -0
- data/lib/generators/saucy/install/templates/create_saucy_tables.rb +1 -0
- data/lib/saucy.rb +2 -0
- data/lib/saucy/account.rb +13 -0
- data/lib/saucy/configuration.rb +3 -3
- data/lib/saucy/cron.rb +8 -0
- data/lib/saucy/layouts.rb +1 -1
- data/lib/saucy/subscription.rb +1 -1
- data/spec/models/account_spec.rb +25 -0
- data/spec/models/subscription_spec.rb +0 -20
- metadata +14 -12
- data/lib/generators/saucy/install/templates/models/invitation_mailer.rb +0 -9
|
@@ -17,4 +17,13 @@ class BillingMailer < ActionMailer::Base
|
|
|
17
17
|
:default => "Problem with subscription billing"),
|
|
18
18
|
:from => Saucy::Configuration.mailer_sender)
|
|
19
19
|
end
|
|
20
|
+
|
|
21
|
+
def expiring_trial(account)
|
|
22
|
+
@account = account
|
|
23
|
+
mail(:to => account.customer.email,
|
|
24
|
+
:subject => I18n.t(:subject,
|
|
25
|
+
:scope => [:saucy, :mailers, :billing_mailer, :expiring_tiral],
|
|
26
|
+
:default => "Your trial is expiring soon"),
|
|
27
|
+
:from => Saucy::Configuration.mailer_sender)
|
|
28
|
+
end
|
|
20
29
|
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
class InvitationMailer < ActionMailer::Base
|
|
2
|
+
def invitation(invitation)
|
|
3
|
+
@invitation = invitation
|
|
4
|
+
subject = I18n.t(:subject,
|
|
5
|
+
:scope => [:saucy, :mailers, :invitation_mailer, :invititation],
|
|
6
|
+
:default => "Invitation")
|
|
7
|
+
mail :to => invitation.email,
|
|
8
|
+
:subject => subject,
|
|
9
|
+
:from => Saucy::Configuration.mailer_sender
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Thanks for giving us a try!
|
|
2
|
+
|
|
3
|
+
Your 30 day trial for <%= @account.name %> is expiring soon. We hope that
|
|
4
|
+
you've enjoyed <%= t("app_name") %> enough to sign up for a paid subscription.
|
|
5
|
+
If you'd like to continue using your account, please take a moment to choose
|
|
6
|
+
a paid plan:
|
|
7
|
+
|
|
8
|
+
<%= edit_account_plan_url(@account) %>
|
|
9
|
+
|
|
10
|
+
If you need more time to evaluate <%= t("app_name") %> or you have any questions,
|
|
11
|
+
please don't hesitate to contact us.
|
|
12
|
+
|
|
13
|
+
<%= t("support_contact_info") %>
|
|
14
|
+
|
|
15
|
+
============================================================
|
|
16
|
+
|
|
17
|
+
Thanks for your business,
|
|
18
|
+
The <%= t("app_name") %> Team
|
|
19
|
+
<%= t("app_url") %>
|
data/config/locales/en.yml
CHANGED
|
@@ -55,3 +55,13 @@ Feature: Trial plans
|
|
|
55
55
|
Then I should see "Test"
|
|
56
56
|
And I should not see "expired"
|
|
57
57
|
|
|
58
|
+
Scenario: Receive a reminder about an expiring trial plan
|
|
59
|
+
Given the following account exists:
|
|
60
|
+
| plan | name | billing email |
|
|
61
|
+
| name: Temp | Test | admin@example.com |
|
|
62
|
+
And the "Test" account was created 23 days ago
|
|
63
|
+
And I am signed in as an admin of the "Test" account
|
|
64
|
+
When the daily Saucy jobs are processed
|
|
65
|
+
And I follow the link sent to "admin@example.com"
|
|
66
|
+
Then I should be on the upgrade plan page for the "Test" account
|
|
67
|
+
|
|
@@ -3,3 +3,9 @@ Given /^an? "([^"]+)" account exists with a name of "([^"]*)" created (\d+) days
|
|
|
3
3
|
Factory(:account, :created_at => days.to_i.days.ago, :plan => plan, :name => account_name)
|
|
4
4
|
end
|
|
5
5
|
|
|
6
|
+
Given /^the "([^"]*)" account was created (\d+) days ago$/ do |account_name, days|
|
|
7
|
+
Account.find_by_name!(account_name).tap do |account|
|
|
8
|
+
account.created_at = days.to_i.days.ago
|
|
9
|
+
account.save!
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -20,6 +20,7 @@ class CreateSaucyTables < ActiveRecord::Migration
|
|
|
20
20
|
table.string :subscription_token
|
|
21
21
|
table.string :subscription_status
|
|
22
22
|
table.datetime :next_billing_date
|
|
23
|
+
table.boolean :notified_of_expiration, :default => false, :null => false
|
|
23
24
|
end
|
|
24
25
|
add_index :accounts, :plan_id
|
|
25
26
|
add_index :accounts, :keyword
|
data/lib/saucy.rb
CHANGED
data/lib/saucy/account.rb
CHANGED
|
@@ -59,5 +59,18 @@ module Saucy
|
|
|
59
59
|
created_at < 30.days.ago
|
|
60
60
|
end
|
|
61
61
|
end
|
|
62
|
+
|
|
63
|
+
module ClassMethods
|
|
64
|
+
def deliver_expiring_trial_notifications
|
|
65
|
+
trial_expiring.each { |account| BillingMailer.expiring_trial(account).deliver }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def trial_expiring
|
|
69
|
+
joins(:plan).
|
|
70
|
+
where(:plans => { :trial => true }).
|
|
71
|
+
where(:notified_of_expiration => false).
|
|
72
|
+
where(["accounts.created_at <= ?", 23.days.ago])
|
|
73
|
+
end
|
|
74
|
+
end
|
|
62
75
|
end
|
|
63
76
|
end
|
data/lib/saucy/configuration.rb
CHANGED
|
@@ -2,12 +2,12 @@ require 'saucy/layouts'
|
|
|
2
2
|
|
|
3
3
|
module Saucy
|
|
4
4
|
class Configuration
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
cattr_reader :layouts
|
|
6
|
+
cattr_reader :mailer_sender
|
|
7
7
|
|
|
8
8
|
def initialize
|
|
9
9
|
@@mailer_sender = 'donotreply@example.com'
|
|
10
|
-
|
|
10
|
+
@@layouts = Layouts.new
|
|
11
11
|
end
|
|
12
12
|
end
|
|
13
13
|
end
|
data/lib/saucy/cron.rb
ADDED
data/lib/saucy/layouts.rb
CHANGED
|
@@ -12,7 +12,7 @@ module Saucy
|
|
|
12
12
|
lambda do |controller|
|
|
13
13
|
controller_name = controller.controller_name
|
|
14
14
|
action_name = controller.action_name
|
|
15
|
-
|
|
15
|
+
Saucy::Configuration.layouts.send(controller_name).send(action_name)
|
|
16
16
|
end
|
|
17
17
|
end
|
|
18
18
|
|
data/lib/saucy/subscription.rb
CHANGED
|
@@ -213,7 +213,7 @@ module Saucy
|
|
|
213
213
|
|
|
214
214
|
module ClassMethods
|
|
215
215
|
def update_subscriptions!
|
|
216
|
-
recently_billed = where("next_billing_date <=
|
|
216
|
+
recently_billed = where("next_billing_date <= '#{Time.now}'")
|
|
217
217
|
recently_billed.each do |account|
|
|
218
218
|
account.subscription_status = account.subscription.status
|
|
219
219
|
account.next_billing_date = account.subscription.next_billing_date
|
data/spec/models/account_spec.rb
CHANGED
|
@@ -80,4 +80,29 @@ describe Account do
|
|
|
80
80
|
forever = Factory(:plan, :trial => false)
|
|
81
81
|
Factory(:account, :created_at => 30.days.ago, :plan => forever).should_not be_expired
|
|
82
82
|
end
|
|
83
|
+
|
|
84
|
+
it "sends notifications for expiring accounts" do
|
|
85
|
+
trial = Factory(:plan, :trial => true)
|
|
86
|
+
forever = Factory(:plan, :trial => false)
|
|
87
|
+
|
|
88
|
+
expiring = [Factory(:account, :plan => trial, :created_at => 23.days.ago),
|
|
89
|
+
Factory(:account, :plan => trial, :created_at => 24.days.ago)]
|
|
90
|
+
forever = Factory(:account, :plan => forever, :created_at => 23.days.ago)
|
|
91
|
+
new_trial = Factory(:account, :plan => trial, :created_at => 22.days.ago)
|
|
92
|
+
already_notified = Factory(:account, :plan => trial,
|
|
93
|
+
:created_at => 24.days.ago,
|
|
94
|
+
:notified_of_expiration => true)
|
|
95
|
+
|
|
96
|
+
mail = stub('mail', :deliver => true)
|
|
97
|
+
BillingMailer.stubs(:expiring_trial => mail)
|
|
98
|
+
|
|
99
|
+
Account.deliver_expiring_trial_notifications
|
|
100
|
+
|
|
101
|
+
expiring.each do |account|
|
|
102
|
+
BillingMailer.should have_received(:expiring_trial).with(account)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
mail.should have_received(:deliver).twice
|
|
106
|
+
end
|
|
83
107
|
end
|
|
108
|
+
|
|
@@ -309,26 +309,6 @@ describe Account, "with a paid subscription" do
|
|
|
309
309
|
end
|
|
310
310
|
end
|
|
311
311
|
|
|
312
|
-
it "doesn't receive a receipt email when it's already been billed" do
|
|
313
|
-
subscription = FakeBraintree.subscriptions[subject.subscription_token]
|
|
314
|
-
subscription["status"] = Braintree::Subscription::Status::Active
|
|
315
|
-
subscription["next_billing_date"] = 2.months.from_now
|
|
316
|
-
FakeBraintree.transaction = { :status => Braintree::Transaction::Status::Settled,
|
|
317
|
-
:subscription_id => subject.subscription_token }
|
|
318
|
-
subscription["transactions"] = [FakeBraintree.generated_transaction]
|
|
319
|
-
|
|
320
|
-
Timecop.travel(subject.next_billing_date - 1.day) do
|
|
321
|
-
ActionMailer::Base.deliveries.clear
|
|
322
|
-
|
|
323
|
-
Account.update_subscriptions!
|
|
324
|
-
|
|
325
|
-
ActionMailer::Base.deliveries.select do |email|
|
|
326
|
-
email.to == [subject.billing_email] &&
|
|
327
|
-
email.subject =~ /receipt/i
|
|
328
|
-
end.should be_empty
|
|
329
|
-
end
|
|
330
|
-
end
|
|
331
|
-
|
|
332
312
|
it "receives a receipt email at it's billing email with a notice that it failed when billing didn't work" do
|
|
333
313
|
subscription = FakeBraintree.subscriptions[subject.subscription_token]
|
|
334
314
|
subscription["status"] = Braintree::Subscription::Status::PastDue
|
metadata
CHANGED
|
@@ -6,9 +6,8 @@ version: !ruby/object:Gem::Version
|
|
|
6
6
|
segments:
|
|
7
7
|
- 0
|
|
8
8
|
- 2
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
version: 0.2.28.1
|
|
9
|
+
- 29
|
|
10
|
+
version: 0.2.29
|
|
12
11
|
platform: ruby
|
|
13
12
|
authors:
|
|
14
13
|
- thoughtbot, inc.
|
|
@@ -18,7 +17,7 @@ autorequire:
|
|
|
18
17
|
bindir: bin
|
|
19
18
|
cert_chain: []
|
|
20
19
|
|
|
21
|
-
date: 2011-
|
|
20
|
+
date: 2011-02-25 00:00:00 -05:00
|
|
22
21
|
default_executable:
|
|
23
22
|
dependencies:
|
|
24
23
|
- !ruby/object:Gem::Dependency
|
|
@@ -33,8 +32,8 @@ dependencies:
|
|
|
33
32
|
- 1
|
|
34
33
|
- 2
|
|
35
34
|
version: "1.2"
|
|
36
|
-
version_requirements: *id001
|
|
37
35
|
name: formtastic
|
|
36
|
+
version_requirements: *id001
|
|
38
37
|
prerelease: false
|
|
39
38
|
- !ruby/object:Gem::Dependency
|
|
40
39
|
type: :runtime
|
|
@@ -49,8 +48,8 @@ dependencies:
|
|
|
49
48
|
- 0
|
|
50
49
|
- 3
|
|
51
50
|
version: 3.0.3
|
|
52
|
-
version_requirements: *id002
|
|
53
51
|
name: railties
|
|
52
|
+
version_requirements: *id002
|
|
54
53
|
prerelease: false
|
|
55
54
|
- !ruby/object:Gem::Dependency
|
|
56
55
|
type: :runtime
|
|
@@ -65,8 +64,8 @@ dependencies:
|
|
|
65
64
|
- 6
|
|
66
65
|
- 2
|
|
67
66
|
version: 2.6.2
|
|
68
|
-
version_requirements: *id003
|
|
69
67
|
name: braintree
|
|
68
|
+
version_requirements: *id003
|
|
70
69
|
prerelease: false
|
|
71
70
|
- !ruby/object:Gem::Dependency
|
|
72
71
|
type: :runtime
|
|
@@ -81,8 +80,8 @@ dependencies:
|
|
|
81
80
|
- 3
|
|
82
81
|
- 3
|
|
83
82
|
version: 1.3.3
|
|
84
|
-
version_requirements: *id004
|
|
85
83
|
name: sham_rack
|
|
84
|
+
version_requirements: *id004
|
|
86
85
|
prerelease: false
|
|
87
86
|
- !ruby/object:Gem::Dependency
|
|
88
87
|
type: :runtime
|
|
@@ -97,8 +96,8 @@ dependencies:
|
|
|
97
96
|
- 1
|
|
98
97
|
- 2
|
|
99
98
|
version: 1.1.2
|
|
100
|
-
version_requirements: *id005
|
|
101
99
|
name: sinatra
|
|
100
|
+
version_requirements: *id005
|
|
102
101
|
prerelease: false
|
|
103
102
|
- !ruby/object:Gem::Dependency
|
|
104
103
|
type: :development
|
|
@@ -113,8 +112,8 @@ dependencies:
|
|
|
113
112
|
- 2
|
|
114
113
|
- 6
|
|
115
114
|
version: 0.2.6
|
|
116
|
-
version_requirements: *id006
|
|
117
115
|
name: aruba
|
|
116
|
+
version_requirements: *id006
|
|
118
117
|
prerelease: false
|
|
119
118
|
description: Clearance-based Rails engine for Software as a Service (Saas) that provides account and project management
|
|
120
119
|
email: support@thoughtbot.com
|
|
@@ -138,6 +137,7 @@ files:
|
|
|
138
137
|
- app/controllers/plans_controller.rb
|
|
139
138
|
- app/controllers/profiles_controller.rb
|
|
140
139
|
- app/mailers/billing_mailer.rb
|
|
140
|
+
- app/mailers/invitation_mailer.rb
|
|
141
141
|
- app/models/invitation.rb
|
|
142
142
|
- app/models/limit.rb
|
|
143
143
|
- app/models/membership.rb
|
|
@@ -150,6 +150,7 @@ files:
|
|
|
150
150
|
- app/views/accounts/edit.html.erb
|
|
151
151
|
- app/views/accounts/index.html.erb
|
|
152
152
|
- app/views/accounts/new.html.erb
|
|
153
|
+
- app/views/billing_mailer/expiring_trial.text.erb
|
|
153
154
|
- app/views/billing_mailer/problem.html.erb
|
|
154
155
|
- app/views/billing_mailer/problem.text.erb
|
|
155
156
|
- app/views/billing_mailer/receipt.html.erb
|
|
@@ -179,6 +180,7 @@ files:
|
|
|
179
180
|
- lib/generators/saucy/features/templates/factories.rb
|
|
180
181
|
- lib/generators/saucy/features/templates/step_definitions/account_steps.rb
|
|
181
182
|
- lib/generators/saucy/features/templates/step_definitions/braintree_steps.rb
|
|
183
|
+
- lib/generators/saucy/features/templates/step_definitions/cron_steps.rb
|
|
182
184
|
- lib/generators/saucy/features/templates/step_definitions/email_steps.rb
|
|
183
185
|
- lib/generators/saucy/features/templates/step_definitions/factory_girl_steps.rb
|
|
184
186
|
- lib/generators/saucy/features/templates/step_definitions/html_steps.rb
|
|
@@ -191,7 +193,6 @@ files:
|
|
|
191
193
|
- lib/generators/saucy/install/templates/controllers/projects_controller.rb
|
|
192
194
|
- lib/generators/saucy/install/templates/create_saucy_tables.rb
|
|
193
195
|
- lib/generators/saucy/install/templates/models/account.rb
|
|
194
|
-
- lib/generators/saucy/install/templates/models/invitation_mailer.rb
|
|
195
196
|
- lib/generators/saucy/install/templates/models/plan.rb
|
|
196
197
|
- lib/generators/saucy/install/templates/models/project.rb
|
|
197
198
|
- lib/generators/saucy/specs/specs_generator.rb
|
|
@@ -200,6 +201,7 @@ files:
|
|
|
200
201
|
- lib/saucy/account.rb
|
|
201
202
|
- lib/saucy/account_authorization.rb
|
|
202
203
|
- lib/saucy/configuration.rb
|
|
204
|
+
- lib/saucy/cron.rb
|
|
203
205
|
- lib/saucy/engine.rb
|
|
204
206
|
- lib/saucy/fake_braintree.rb
|
|
205
207
|
- lib/saucy/layouts.rb
|
|
@@ -287,7 +289,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
287
289
|
requirements: []
|
|
288
290
|
|
|
289
291
|
rubyforge_project:
|
|
290
|
-
rubygems_version: 1.
|
|
292
|
+
rubygems_version: 1.5.2
|
|
291
293
|
signing_key:
|
|
292
294
|
specification_version: 3
|
|
293
295
|
summary: Clearance-based Rails engine for SaaS
|