saucy 0.2.28.1 → 0.2.29

Sign up to get free protection for your applications and to get access to all the features.
@@ -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") %>
@@ -2,6 +2,7 @@ en:
2
2
  app_name: App Name
3
3
  app_url: 'http://example.com'
4
4
  support_email: support@example.com
5
+ supprt_contact_info: support@example.com
5
6
  saucy:
6
7
  billing_address: Billing Address
7
8
  errors:
@@ -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
@@ -0,0 +1,4 @@
1
+ When /^the daily Saucy jobs are processed$/ do
2
+ Saucy::Cron.run_daily
3
+ end
4
+
@@ -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
@@ -7,3 +7,5 @@ require 'saucy/account_authorization'
7
7
  require 'saucy/configuration'
8
8
  require 'saucy/engine'
9
9
  require 'saucy/projects_controller'
10
+ require 'saucy/cron'
11
+
@@ -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
@@ -2,12 +2,12 @@ require 'saucy/layouts'
2
2
 
3
3
  module Saucy
4
4
  class Configuration
5
- attr_reader :layouts
6
- cattr_accessor :mailer_sender
5
+ cattr_reader :layouts
6
+ cattr_reader :mailer_sender
7
7
 
8
8
  def initialize
9
9
  @@mailer_sender = 'donotreply@example.com'
10
- @layouts = Layouts.new
10
+ @@layouts = Layouts.new
11
11
  end
12
12
  end
13
13
  end
@@ -0,0 +1,8 @@
1
+ module Saucy
2
+ module Cron
3
+ def self.run_daily
4
+ ::Account.deliver_expiring_trial_notifications
5
+ end
6
+ end
7
+ end
8
+
@@ -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
- Rails.application.config.saucy.layouts.send(controller_name).send(action_name)
15
+ Saucy::Configuration.layouts.send(controller_name).send(action_name)
16
16
  end
17
17
  end
18
18
 
@@ -213,7 +213,7 @@ module Saucy
213
213
 
214
214
  module ClassMethods
215
215
  def update_subscriptions!
216
- recently_billed = where("next_billing_date <= ?", Time.now)
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
@@ -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
- - 28
10
- - 1
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-04-20 00:00:00 -04:00
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.6.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
@@ -1,9 +0,0 @@
1
- class InvitationMailer < ActionMailer::Base
2
- default :from => 'donotreply@example.com'
3
-
4
- def invitation(invitation)
5
- @invitation = invitation
6
- mail :to => invitation.email,
7
- :subject => "Invitation"
8
- end
9
- end