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