saucy 0.10.10 → 0.11.2
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/CHANGELOG.md +8 -8
- data/Gemfile +1 -2
- data/Gemfile.lock +141 -128
- data/README.md +8 -9
- data/Rakefile +2 -2
- data/app/models/invitation.rb +1 -0
- data/app/views/accounts/edit.html.erb +4 -28
- data/app/views/shared/_project_dropdown.html.erb +1 -1
- data/config/locales/en.yml +0 -3
- data/features/run_features.feature +24 -25
- data/features/step_definitions/clearance_steps.rb +3 -3
- data/features/step_definitions/rails_steps.rb +2 -2
- data/features/support/env.rb +5 -2
- data/lib/generators/saucy/features/templates/features/manage_account.feature +1 -12
- data/lib/generators/saucy/features/templates/step_definitions/braintree_steps.rb +1 -1
- data/lib/generators/saucy/features/templates/step_definitions/cron_steps.rb +3 -1
- data/lib/generators/saucy/features/templates/step_definitions/session_steps.rb +2 -2
- data/lib/saucy/configuration.rb +0 -2
- data/lib/saucy/engine.rb +1 -4
- data/lib/saucy/fake_braintree.rb +1 -1
- data/lib/saucy/routing_extensions.rb +2 -7
- data/lib/saucy/subscription.rb +3 -31
- data/public/saucy/stylesheets/screen.css +1 -5
- data/spec/environment.rb +6 -5
- data/spec/models/subscription_spec.rb +14 -68
- data/spec/saucy/configuration_spec.rb +0 -14
- data/spec/spec_helper.rb +2 -2
- data/spec/support/clearance_matchers.rb +1 -1
- data/spec/support/notifications.rb +1 -1
- metadata +8 -24
data/CHANGELOG.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.11.0
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Update Saucy to be compatible with Rails 3.1 which includes:
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
* Update testing dependencies
|
|
6
|
+
* Update test application path configuration
|
|
7
|
+
* Update route extension to not rely on `initialize` to be called
|
|
8
|
+
* Use `shoulda-matchers` instead of `shoulda`
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
0.10.8
|
|
10
|
-
|
|
11
|
-
Backport merchant account TZ fixes from 0.13.1
|
|
10
|
+
If you are still using Saucy with Rails 3.0.x, please still use 0.10.x version
|
|
11
|
+
of saucy, which now branched to `0-10-stable` branch.
|
|
12
12
|
|
|
13
13
|
0.10.7
|
|
14
14
|
|
data/Gemfile
CHANGED
|
@@ -6,7 +6,7 @@ gem "rspec-rails", :require => false
|
|
|
6
6
|
gem "rails", ">= 3.0.3"
|
|
7
7
|
gem "thin"
|
|
8
8
|
gem "clearance", "~> 0.11.0"
|
|
9
|
-
gem "shoulda", :require => false
|
|
9
|
+
gem "shoulda-matchers", "~> 1.0.0.beta3", :require => false
|
|
10
10
|
gem "bourne", :require => false
|
|
11
11
|
gem "sqlite3", :require => false
|
|
12
12
|
gem "factory_girl", :require => false
|
|
@@ -14,7 +14,6 @@ gem "sinatra"
|
|
|
14
14
|
gem "sham_rack"
|
|
15
15
|
gem "braintree"
|
|
16
16
|
gem "timecop"
|
|
17
|
-
gem "airbrake"
|
|
18
17
|
|
|
19
18
|
# used by the rails app in cucumber
|
|
20
19
|
gem "cucumber-rails", :require => false
|
data/Gemfile.lock
CHANGED
|
@@ -1,176 +1,189 @@
|
|
|
1
1
|
GEM
|
|
2
2
|
remote: http://rubygems.org/
|
|
3
3
|
specs:
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
rack (~> 1.
|
|
15
|
-
rack-mount (~> 0.
|
|
16
|
-
rack-test (~> 0.
|
|
17
|
-
|
|
18
|
-
activemodel (3.0
|
|
19
|
-
activesupport (= 3.0
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
arel (2.
|
|
35
|
-
aruba (0.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
4
|
+
actionmailer (3.1.0)
|
|
5
|
+
actionpack (= 3.1.0)
|
|
6
|
+
mail (~> 2.3.0)
|
|
7
|
+
actionpack (3.1.0)
|
|
8
|
+
activemodel (= 3.1.0)
|
|
9
|
+
activesupport (= 3.1.0)
|
|
10
|
+
builder (~> 3.0.0)
|
|
11
|
+
erubis (~> 2.7.0)
|
|
12
|
+
i18n (~> 0.6)
|
|
13
|
+
rack (~> 1.3.2)
|
|
14
|
+
rack-cache (~> 1.0.3)
|
|
15
|
+
rack-mount (~> 0.8.2)
|
|
16
|
+
rack-test (~> 0.6.1)
|
|
17
|
+
sprockets (~> 2.0.0)
|
|
18
|
+
activemodel (3.1.0)
|
|
19
|
+
activesupport (= 3.1.0)
|
|
20
|
+
bcrypt-ruby (~> 3.0.0)
|
|
21
|
+
builder (~> 3.0.0)
|
|
22
|
+
i18n (~> 0.6)
|
|
23
|
+
activerecord (3.1.0)
|
|
24
|
+
activemodel (= 3.1.0)
|
|
25
|
+
activesupport (= 3.1.0)
|
|
26
|
+
arel (~> 2.2.1)
|
|
27
|
+
tzinfo (~> 0.3.29)
|
|
28
|
+
activeresource (3.1.0)
|
|
29
|
+
activemodel (= 3.1.0)
|
|
30
|
+
activesupport (= 3.1.0)
|
|
31
|
+
activesupport (3.1.0)
|
|
32
|
+
multi_json (~> 1.0)
|
|
33
|
+
addressable (2.2.6)
|
|
34
|
+
arel (2.2.1)
|
|
35
|
+
aruba (0.4.6)
|
|
36
|
+
bcat (>= 0.6.1)
|
|
37
|
+
childprocess (>= 0.2.0)
|
|
38
|
+
cucumber (>= 1.0.2)
|
|
39
|
+
rdiscount (>= 1.6.8)
|
|
40
|
+
rspec (>= 2.6.0)
|
|
41
|
+
bcat (0.6.2)
|
|
42
|
+
rack (~> 1.0)
|
|
43
|
+
bcrypt-ruby (3.0.0)
|
|
39
44
|
bourne (1.0)
|
|
40
45
|
mocha (= 0.9.8)
|
|
41
|
-
braintree (2.
|
|
42
|
-
builder
|
|
43
|
-
builder (
|
|
44
|
-
capybara (
|
|
45
|
-
celerity (>= 0.7.9)
|
|
46
|
-
culerity (>= 0.2.4)
|
|
46
|
+
braintree (2.11.0)
|
|
47
|
+
builder (>= 2.0.0)
|
|
48
|
+
builder (3.0.0)
|
|
49
|
+
capybara (1.1.1)
|
|
47
50
|
mime-types (>= 1.16)
|
|
48
51
|
nokogiri (>= 1.3.3)
|
|
49
52
|
rack (>= 1.0.0)
|
|
50
53
|
rack-test (>= 0.5.4)
|
|
51
|
-
selenium-webdriver (
|
|
52
|
-
xpath (~> 0.1.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
clearance (0.11.1)
|
|
54
|
+
selenium-webdriver (~> 2.0)
|
|
55
|
+
xpath (~> 0.1.4)
|
|
56
|
+
childprocess (0.2.2)
|
|
57
|
+
ffi (~> 1.0.6)
|
|
58
|
+
clearance (0.11.2)
|
|
57
59
|
diesel (~> 0.1.4)
|
|
58
|
-
rails (
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
cucumber (
|
|
68
|
-
|
|
69
|
-
daemons (1.1.
|
|
70
|
-
database_cleaner (0.6.
|
|
71
|
-
diesel (0.1.
|
|
72
|
-
railties
|
|
73
|
-
diff-lcs (1.1.
|
|
74
|
-
dynamic_form (1.1.
|
|
75
|
-
erubis (2.
|
|
76
|
-
abstract (>= 1.0.0)
|
|
60
|
+
rails (>= 3.0)
|
|
61
|
+
cucumber (1.0.4)
|
|
62
|
+
builder (>= 2.1.2)
|
|
63
|
+
diff-lcs (>= 1.1.2)
|
|
64
|
+
gherkin (~> 2.4.18)
|
|
65
|
+
json (>= 1.4.6)
|
|
66
|
+
term-ansicolor (>= 1.0.6)
|
|
67
|
+
cucumber-rails (1.0.3)
|
|
68
|
+
capybara (>= 1.1.1)
|
|
69
|
+
cucumber (~> 1.0.4)
|
|
70
|
+
nokogiri (>= 1.5.0)
|
|
71
|
+
daemons (1.1.4)
|
|
72
|
+
database_cleaner (0.6.7)
|
|
73
|
+
diesel (0.1.5)
|
|
74
|
+
railties
|
|
75
|
+
diff-lcs (1.1.3)
|
|
76
|
+
dynamic_form (1.1.4)
|
|
77
|
+
erubis (2.7.0)
|
|
77
78
|
eventmachine (0.12.10)
|
|
78
|
-
factory_girl (1.
|
|
79
|
-
factory_girl_rails (1.0)
|
|
80
|
-
factory_girl (~> 1.
|
|
81
|
-
|
|
82
|
-
ffi (0.
|
|
83
|
-
|
|
84
|
-
formtastic (1.2.2)
|
|
79
|
+
factory_girl (2.1.0)
|
|
80
|
+
factory_girl_rails (1.2.0)
|
|
81
|
+
factory_girl (~> 2.1.0)
|
|
82
|
+
railties (>= 3.0.0)
|
|
83
|
+
ffi (1.0.9)
|
|
84
|
+
formtastic (1.2.4)
|
|
85
85
|
actionpack (>= 2.3.7)
|
|
86
86
|
activesupport (>= 2.3.7)
|
|
87
|
-
i18n (
|
|
88
|
-
gherkin (2.
|
|
89
|
-
json (
|
|
90
|
-
|
|
91
|
-
i18n (0.
|
|
92
|
-
jquery-rails (1.0)
|
|
93
|
-
|
|
87
|
+
i18n (~> 0.4)
|
|
88
|
+
gherkin (2.4.18)
|
|
89
|
+
json (>= 1.4.6)
|
|
90
|
+
hike (1.2.1)
|
|
91
|
+
i18n (0.6.0)
|
|
92
|
+
jquery-rails (1.0.14)
|
|
93
|
+
railties (~> 3.0)
|
|
94
94
|
thor (~> 0.14)
|
|
95
|
-
json (1.4
|
|
96
|
-
json_pure (1.5.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
mail (2.
|
|
101
|
-
activesupport (>= 2.3.6)
|
|
95
|
+
json (1.5.4)
|
|
96
|
+
json_pure (1.5.4)
|
|
97
|
+
spruz (~> 0.2.8)
|
|
98
|
+
launchy (2.0.5)
|
|
99
|
+
addressable (~> 2.2.6)
|
|
100
|
+
mail (2.3.0)
|
|
102
101
|
i18n (>= 0.4.0)
|
|
103
102
|
mime-types (~> 1.16)
|
|
104
103
|
treetop (~> 1.4.8)
|
|
105
104
|
mime-types (1.16)
|
|
106
105
|
mocha (0.9.8)
|
|
107
106
|
rake
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
rack
|
|
107
|
+
multi_json (1.0.3)
|
|
108
|
+
nokogiri (1.5.0)
|
|
109
|
+
polyglot (0.3.2)
|
|
110
|
+
rack (1.3.2)
|
|
111
|
+
rack-cache (1.0.3)
|
|
112
|
+
rack (>= 0.4)
|
|
113
|
+
rack-mount (0.8.3)
|
|
112
114
|
rack (>= 1.0.0)
|
|
113
|
-
rack-
|
|
115
|
+
rack-ssl (1.3.2)
|
|
116
|
+
rack
|
|
117
|
+
rack-test (0.6.1)
|
|
114
118
|
rack (>= 1.0)
|
|
115
|
-
rails (3.0
|
|
116
|
-
actionmailer (= 3.0
|
|
117
|
-
actionpack (= 3.0
|
|
118
|
-
activerecord (= 3.0
|
|
119
|
-
activeresource (= 3.0
|
|
120
|
-
activesupport (= 3.0
|
|
119
|
+
rails (3.1.0)
|
|
120
|
+
actionmailer (= 3.1.0)
|
|
121
|
+
actionpack (= 3.1.0)
|
|
122
|
+
activerecord (= 3.1.0)
|
|
123
|
+
activeresource (= 3.1.0)
|
|
124
|
+
activesupport (= 3.1.0)
|
|
121
125
|
bundler (~> 1.0)
|
|
122
|
-
railties (= 3.0
|
|
123
|
-
railties (3.0
|
|
124
|
-
actionpack (= 3.0
|
|
125
|
-
activesupport (= 3.0
|
|
126
|
+
railties (= 3.1.0)
|
|
127
|
+
railties (3.1.0)
|
|
128
|
+
actionpack (= 3.1.0)
|
|
129
|
+
activesupport (= 3.1.0)
|
|
130
|
+
rack-ssl (~> 1.3.2)
|
|
126
131
|
rake (>= 0.8.7)
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
132
|
+
rdoc (~> 3.4)
|
|
133
|
+
thor (~> 0.14.6)
|
|
134
|
+
rake (0.9.2)
|
|
135
|
+
rdiscount (1.6.8)
|
|
136
|
+
rdoc (3.9.4)
|
|
137
|
+
rspec (2.6.0)
|
|
138
|
+
rspec-core (~> 2.6.0)
|
|
139
|
+
rspec-expectations (~> 2.6.0)
|
|
140
|
+
rspec-mocks (~> 2.6.0)
|
|
141
|
+
rspec-core (2.6.4)
|
|
142
|
+
rspec-expectations (2.6.0)
|
|
135
143
|
diff-lcs (~> 1.1.2)
|
|
136
|
-
rspec-mocks (2.
|
|
137
|
-
rspec-rails (2.
|
|
144
|
+
rspec-mocks (2.6.0)
|
|
145
|
+
rspec-rails (2.6.1)
|
|
138
146
|
actionpack (~> 3.0)
|
|
139
147
|
activesupport (~> 3.0)
|
|
140
148
|
railties (~> 3.0)
|
|
141
|
-
rspec (~> 2.
|
|
149
|
+
rspec (~> 2.6.0)
|
|
142
150
|
rubyzip (0.9.4)
|
|
143
|
-
selenium-webdriver (
|
|
144
|
-
childprocess (
|
|
145
|
-
ffi (
|
|
151
|
+
selenium-webdriver (2.5.0)
|
|
152
|
+
childprocess (>= 0.2.1)
|
|
153
|
+
ffi (>= 1.0.7)
|
|
146
154
|
json_pure
|
|
147
155
|
rubyzip
|
|
148
156
|
sham_rack (1.3.3)
|
|
149
157
|
rack
|
|
150
|
-
shoulda (
|
|
151
|
-
sinatra (1.
|
|
158
|
+
shoulda-matchers (1.0.0.beta3)
|
|
159
|
+
sinatra (1.2.6)
|
|
152
160
|
rack (~> 1.1)
|
|
153
|
-
tilt (
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
161
|
+
tilt (< 2.0, >= 1.2.2)
|
|
162
|
+
sprockets (2.0.0)
|
|
163
|
+
hike (~> 1.2)
|
|
164
|
+
rack (~> 1.0)
|
|
165
|
+
tilt (!= 1.3.0, ~> 1.1)
|
|
166
|
+
spruz (0.2.13)
|
|
167
|
+
sqlite3 (1.3.4)
|
|
168
|
+
term-ansicolor (1.0.6)
|
|
169
|
+
thin (1.2.11)
|
|
157
170
|
daemons (>= 1.0.9)
|
|
158
171
|
eventmachine (>= 0.12.6)
|
|
159
172
|
rack (>= 1.0.0)
|
|
160
173
|
thor (0.14.6)
|
|
161
|
-
tilt (1.
|
|
174
|
+
tilt (1.3.3)
|
|
162
175
|
timecop (0.3.5)
|
|
163
|
-
treetop (1.4.
|
|
176
|
+
treetop (1.4.10)
|
|
177
|
+
polyglot
|
|
164
178
|
polyglot (>= 0.3.1)
|
|
165
|
-
tzinfo (0.3.
|
|
166
|
-
xpath (0.1.
|
|
179
|
+
tzinfo (0.3.29)
|
|
180
|
+
xpath (0.1.4)
|
|
167
181
|
nokogiri (~> 1.3)
|
|
168
182
|
|
|
169
183
|
PLATFORMS
|
|
170
184
|
ruby
|
|
171
185
|
|
|
172
186
|
DEPENDENCIES
|
|
173
|
-
airbrake
|
|
174
187
|
aruba
|
|
175
188
|
bourne
|
|
176
189
|
braintree
|
|
@@ -189,7 +202,7 @@ DEPENDENCIES
|
|
|
189
202
|
rake
|
|
190
203
|
rspec-rails
|
|
191
204
|
sham_rack
|
|
192
|
-
shoulda
|
|
205
|
+
shoulda-matchers (~> 1.0.0.beta3)
|
|
193
206
|
sinatra
|
|
194
207
|
sqlite3
|
|
195
208
|
thin
|
data/README.md
CHANGED
|
@@ -21,6 +21,10 @@ In your Gemfile:
|
|
|
21
21
|
|
|
22
22
|
gem "saucy"
|
|
23
23
|
|
|
24
|
+
If you're using Rails 3.0.x, instead use the 0.10.x version of this gem:
|
|
25
|
+
|
|
26
|
+
gem "saucy", "~> 0.10.7"
|
|
27
|
+
|
|
24
28
|
After you bundle, run the generator:
|
|
25
29
|
|
|
26
30
|
rails generate saucy:install
|
|
@@ -53,6 +57,7 @@ followup emails being sent to users that have already set up their accounts.
|
|
|
53
57
|
It will also send an "Activated" event to Kissmetrics through Saucy-kiss, if
|
|
54
58
|
Saucy-kiss is installed.
|
|
55
59
|
|
|
60
|
+
|
|
56
61
|
Development environment
|
|
57
62
|
-----------------------
|
|
58
63
|
|
|
@@ -82,13 +87,13 @@ To use seed data in your Cucumber, add this to features/support/seed.rb:
|
|
|
82
87
|
Customization
|
|
83
88
|
-------------
|
|
84
89
|
|
|
85
|
-
By default Saucy uses and provides a `saucy.html.erb` layout. To change the
|
|
86
|
-
layout for a controller inside of saucy, add a line like this to your
|
|
90
|
+
By default Saucy uses and provides a `saucy.html.erb` layout. To change the
|
|
91
|
+
layout for a controller inside of saucy, add a line like this to your
|
|
87
92
|
config/application.rb:
|
|
88
93
|
|
|
89
94
|
config.saucy.layouts.accounts.index = "custom"
|
|
90
95
|
|
|
91
|
-
In addition to just the normal yield, your layout should yield the following
|
|
96
|
+
In addition to just the normal yield, your layout should yield the following
|
|
92
97
|
items in order to get everything from saucy views:
|
|
93
98
|
|
|
94
99
|
* :header
|
|
@@ -122,9 +127,3 @@ Make sure you don't do this in ApplicationController:
|
|
|
122
127
|
|
|
123
128
|
Saucy's internal controllers don't skip any before filters.
|
|
124
129
|
|
|
125
|
-
If your billing merchant account is not configured to run in the Eastern
|
|
126
|
-
timezone, you can override the timezone in Saucy configuration as
|
|
127
|
-
merchant_account_time_zone. You'll want this set accurately so that the daily
|
|
128
|
-
cronjob which syncs the Braintree subscription billing cycle dates runs for the
|
|
129
|
-
correct accounts. If this is set incorrectly, you will occasionally see
|
|
130
|
-
duplicate receipt emails being delivered.
|
data/Rakefile
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require 'rubygems'
|
|
2
2
|
require 'bundler/setup'
|
|
3
3
|
require 'rake'
|
|
4
|
-
require '
|
|
4
|
+
require 'rubygems/package_task'
|
|
5
5
|
require 'cucumber/rake/task'
|
|
6
6
|
require 'rspec/core/rake_task'
|
|
7
7
|
|
|
@@ -19,7 +19,7 @@ RSpec::Core::RakeTask.new do |t|
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
eval("$specification = begin; #{IO.read('saucy.gemspec')}; end")
|
|
22
|
-
|
|
22
|
+
Gem::PackageTask.new($specification) do |package|
|
|
23
23
|
package.need_zip = true
|
|
24
24
|
package.need_tar = true
|
|
25
25
|
end
|
data/app/models/invitation.rb
CHANGED
|
@@ -24,34 +24,10 @@
|
|
|
24
24
|
<%= form.buttons do %>
|
|
25
25
|
<%= form.commit_button "Update" %>
|
|
26
26
|
<li>
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
</p>
|
|
32
|
-
|
|
33
|
-
<%= link_to t("saucy.confirm_account_deletion", :default => "I understand, delete my account"),
|
|
34
|
-
@account,
|
|
35
|
-
:class => "button warning",
|
|
36
|
-
:method => :delete,
|
|
37
|
-
:confirm => "Are you sure? All data will be irreversibly deleted." %>
|
|
38
|
-
|
|
39
|
-
<%= link_to t("saucy.cancel_account_deletion", :default => "On second thought, don't delete my account."),
|
|
40
|
-
root_path, :class => "cancel-account-deletion" %>
|
|
41
|
-
</div>
|
|
42
|
-
|
|
43
|
-
<%= link_to t(".delete", :default => "Delete my account"), "#", :class => "prompt-to-delete" %>
|
|
44
|
-
|
|
45
|
-
<% content_for :javascript do %>
|
|
46
|
-
<script type="text/javascript">
|
|
47
|
-
$(function() {
|
|
48
|
-
$("a.prompt-to-delete").click(function(event) {
|
|
49
|
-
$(event.target).hide();
|
|
50
|
-
$('#account-deletion-warning').slideDown();
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
</script>
|
|
54
|
-
<% end %>
|
|
27
|
+
<%= link_to t(".delete", :default => "Delete my account"),
|
|
28
|
+
@account,
|
|
29
|
+
:method => :delete,
|
|
30
|
+
:confirm => "Are you sure? All data will be irreversibly deleted." %>
|
|
55
31
|
</li>
|
|
56
32
|
<% end %>
|
|
57
33
|
<% end %>
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
<span>Projects</span>
|
|
10
10
|
<% end -%>
|
|
11
11
|
<% if current_user.memberships.admin.any? || current_user.projects.active.any? -%>
|
|
12
|
-
|
|
12
|
+
<%= image_tag "arrow-down.png", :alt => "arrow down" %>
|
|
13
13
|
<% end -%>
|
|
14
14
|
<% end %>
|
|
15
15
|
</h1>
|
data/config/locales/en.yml
CHANGED
|
@@ -3,9 +3,6 @@ en:
|
|
|
3
3
|
app_url: 'http://example.com'
|
|
4
4
|
support_email: support@example.com
|
|
5
5
|
saucy:
|
|
6
|
-
account_deletion_effects_warning: When you cancel your account, all of your data will be deleted from %{app_name}, and you will not be able to recover your data.
|
|
7
|
-
cancel_account_deletion: On second thought, don't delete my account.
|
|
8
|
-
confirm_account_deletion: I understand, delete my account
|
|
9
6
|
billing_address: Billing Address
|
|
10
7
|
errors:
|
|
11
8
|
past_due:
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Feature: generate a saucy application and run rake
|
|
3
3
|
|
|
4
4
|
Background:
|
|
5
|
-
When I successfully run
|
|
5
|
+
When I successfully run `bundle exec rails new testapp`
|
|
6
6
|
And I cd to "testapp"
|
|
7
7
|
And I copy the locked Gemfile from this project
|
|
8
8
|
And I append to "Gemfile" with:
|
|
@@ -16,23 +16,22 @@ Feature: generate a saucy application and run rake
|
|
|
16
16
|
gem "formtastic"
|
|
17
17
|
gem "rspec-rails"
|
|
18
18
|
gem "bourne"
|
|
19
|
-
gem "shoulda"
|
|
19
|
+
gem "shoulda-matchers"
|
|
20
20
|
gem "launchy"
|
|
21
21
|
gem "timecop"
|
|
22
22
|
gem "jquery-rails"
|
|
23
23
|
"""
|
|
24
24
|
When I add the "saucy" gem from this project as a dependency
|
|
25
|
-
And I successfully run
|
|
26
|
-
And I successfully run "rails generate jquery:install --force"
|
|
25
|
+
And I successfully run `bundle install`
|
|
27
26
|
And I bootstrap the application for clearance
|
|
28
27
|
And I bootstrap the application for saucy
|
|
29
28
|
|
|
30
29
|
Scenario: generate a saucy application and run rake
|
|
31
|
-
When I successfully run
|
|
32
|
-
And I successfully run
|
|
33
|
-
And I successfully run
|
|
34
|
-
And I successfully run
|
|
35
|
-
And I run
|
|
30
|
+
When I successfully run `rails generate saucy:install`
|
|
31
|
+
And I successfully run `rails generate saucy:specs`
|
|
32
|
+
And I successfully run `rails generate saucy:features`
|
|
33
|
+
And I successfully run `bundle exec rake db:migrate`
|
|
34
|
+
And I run `bundle exec rake`
|
|
36
35
|
Then it should pass with:
|
|
37
36
|
"""
|
|
38
37
|
passed
|
|
@@ -41,13 +40,13 @@ Feature: generate a saucy application and run rake
|
|
|
41
40
|
And the output should not contain "Could not find generator"
|
|
42
41
|
|
|
43
42
|
Scenario: A new saucy app with custom views
|
|
44
|
-
When I successfully run
|
|
45
|
-
And I successfully run
|
|
46
|
-
And I successfully run
|
|
47
|
-
And I successfully run
|
|
48
|
-
And I successfully run
|
|
43
|
+
When I successfully run `rails generate saucy:install`
|
|
44
|
+
And I successfully run `rails generate saucy:specs`
|
|
45
|
+
And I successfully run `rails generate saucy:features`
|
|
46
|
+
And I successfully run `rails generate saucy:views`
|
|
47
|
+
And I successfully run `bundle exec rake db:migrate`
|
|
49
48
|
And I give a more detailed new account message
|
|
50
|
-
And I run
|
|
49
|
+
And I run `bundle exec rake`
|
|
51
50
|
Then it should pass with:
|
|
52
51
|
"""
|
|
53
52
|
passed
|
|
@@ -56,12 +55,12 @@ Feature: generate a saucy application and run rake
|
|
|
56
55
|
And the output should not contain "Could not find generator"
|
|
57
56
|
|
|
58
57
|
Scenario: A new saucy app with custom layouts
|
|
59
|
-
When I successfully run
|
|
60
|
-
And I successfully run
|
|
61
|
-
And I successfully run
|
|
62
|
-
And I successfully run
|
|
58
|
+
When I successfully run `rails generate saucy:install`
|
|
59
|
+
And I successfully run `rails generate saucy:specs`
|
|
60
|
+
And I successfully run `rails generate saucy:features`
|
|
61
|
+
And I successfully run `bundle exec rake db:migrate`
|
|
63
62
|
And I add a custom layout to the accounts index
|
|
64
|
-
And I run
|
|
63
|
+
And I run `bundle exec rake`
|
|
65
64
|
Then it should pass with:
|
|
66
65
|
"""
|
|
67
66
|
passed
|
|
@@ -70,12 +69,12 @@ Feature: generate a saucy application and run rake
|
|
|
70
69
|
And the output should not contain "Could not find generator"
|
|
71
70
|
|
|
72
71
|
Scenario: run specs
|
|
73
|
-
When I successfully run
|
|
74
|
-
And I successfully run
|
|
75
|
-
And I successfully run
|
|
76
|
-
And I successfully run
|
|
72
|
+
When I successfully run `rails generate saucy:install`
|
|
73
|
+
And I successfully run `rails generate saucy:specs`
|
|
74
|
+
And I successfully run `rails generate saucy:features`
|
|
75
|
+
And I successfully run `bundle exec rake db:migrate`
|
|
77
76
|
And I copy the specs for this project
|
|
78
|
-
And I run
|
|
77
|
+
And I run `bundle exec rake spec`
|
|
79
78
|
Then it should pass with:
|
|
80
79
|
"""
|
|
81
80
|
0 failures
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
When /^I bootstrap the application for clearance$/ do
|
|
2
2
|
steps %{
|
|
3
3
|
When I remove the file "public/index.html"
|
|
4
|
-
And I successfully run
|
|
5
|
-
And I successfully run
|
|
6
|
-
And I successfully run
|
|
4
|
+
And I successfully run `rails generate cucumber:install`
|
|
5
|
+
And I successfully run `rails generate clearance:install`
|
|
6
|
+
And I successfully run `rails generate clearance:features`
|
|
7
7
|
And I configure ActionMailer to use "www.example.com" as a host
|
|
8
8
|
And I add flash messages to the layout
|
|
9
9
|
And I add session links to the layout
|
|
@@ -28,7 +28,7 @@ When /^I give a more detailed new account message$/ do
|
|
|
28
28
|
When I go to the sign up page for the "Free" plan
|
|
29
29
|
Then I should see "Please sign up now"
|
|
30
30
|
HERE
|
|
31
|
-
|
|
31
|
+
write_file('features/new_account_message.feature', scenario)
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
When /^I add a custom layout to the accounts index$/ do
|
|
@@ -44,7 +44,7 @@ When /^I add a custom layout to the accounts index$/ do
|
|
|
44
44
|
/(class .* < Rails::Application)/,
|
|
45
45
|
"\\1\n#{layout_config}"
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
write_file('features/custom_accounts_index_layout.feature', <<-SCENARIO)
|
|
48
48
|
Feature: The accounts index should have a custom layout
|
|
49
49
|
Scenario: Custom layout
|
|
50
50
|
Given I am signed up as "email@person.com"
|
data/features/support/env.rb
CHANGED
|
@@ -24,23 +24,12 @@ Feature: Manage account
|
|
|
24
24
|
When I follow "Users"
|
|
25
25
|
Then I should see "captain@awesome.com"
|
|
26
26
|
|
|
27
|
-
@javascript
|
|
28
27
|
Scenario: Delete account
|
|
29
28
|
Given an account exists with a name of "Chocolate"
|
|
30
29
|
And I am signed in as an admin of the "Chocolate" account
|
|
31
30
|
When I go to the settings page for the "Chocolate" account
|
|
32
|
-
And I follow "Delete
|
|
33
|
-
Then I should see "Warning"
|
|
34
|
-
When I follow "I understand"
|
|
31
|
+
And I follow "Delete"
|
|
35
32
|
Then I should see "Your account has been deleted"
|
|
36
33
|
When I go to the dashboard page
|
|
37
34
|
Then I should not see "Chocolate"
|
|
38
35
|
|
|
39
|
-
@javascript
|
|
40
|
-
Scenario: Cancel deleting account
|
|
41
|
-
Given an account exists with a name of "Chocolate"
|
|
42
|
-
And I am signed in as an admin of the "Chocolate" account
|
|
43
|
-
When I go to the settings page for the "Chocolate" account
|
|
44
|
-
And I follow "Delete my account"
|
|
45
|
-
And I follow "don't delete my account"
|
|
46
|
-
Then I should not see "Your account has been deleted"
|
|
@@ -18,7 +18,7 @@ Given /^the following transaction exist for the "([^"]*)" account:$/ do |account
|
|
|
18
18
|
table.hashes.each do |transaction|
|
|
19
19
|
FakeBraintree.transaction = { :status => transaction["status"],
|
|
20
20
|
:amount => transaction["amount"],
|
|
21
|
-
:created_at =>
|
|
21
|
+
:created_at => DateTime.parse(transaction["created_at"]),
|
|
22
22
|
:subscription_id => account.subscription_token }
|
|
23
23
|
subscription["transactions"] << FakeBraintree.generated_transaction
|
|
24
24
|
end
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
require 'rake'
|
|
2
2
|
|
|
3
3
|
module RakeHelpers
|
|
4
|
+
include Rake::DSL
|
|
5
|
+
|
|
4
6
|
def fake_rake
|
|
5
7
|
old_rake = Rake.application
|
|
6
8
|
rake = Rake::Application.new
|
|
@@ -16,7 +18,7 @@ World(RakeHelpers)
|
|
|
16
18
|
|
|
17
19
|
When /^the daily Saucy jobs are processed$/ do
|
|
18
20
|
fake_rake do |rake|
|
|
19
|
-
Saucy::Engine.
|
|
21
|
+
Saucy::Engine.load_tasks
|
|
20
22
|
rake['saucy:daily'].invoke
|
|
21
23
|
end
|
|
22
24
|
end
|
|
@@ -33,6 +33,6 @@ end
|
|
|
33
33
|
When /^I authenticate as the site owner$/ do
|
|
34
34
|
name, password = Saucy::Configuration.admin_username, Saucy::Configuration.admin_password
|
|
35
35
|
# This is done differently in various capybara versions, you may need to change it to
|
|
36
|
-
# page.driver.
|
|
37
|
-
page.driver.basic_authorize name, password
|
|
36
|
+
# page.driver.basic_authorize - or - page.driver.basic_auth
|
|
37
|
+
page.driver.browser.basic_authorize name, password
|
|
38
38
|
end
|
data/lib/saucy/configuration.rb
CHANGED
|
@@ -8,7 +8,6 @@ module Saucy
|
|
|
8
8
|
cattr_accessor :merchant_account_id
|
|
9
9
|
cattr_accessor :admin_username
|
|
10
10
|
cattr_accessor :admin_password
|
|
11
|
-
cattr_accessor :merchant_account_time_zone
|
|
12
11
|
|
|
13
12
|
def initialize
|
|
14
13
|
@@manager_email_address = 'manager@example.com'
|
|
@@ -16,7 +15,6 @@ module Saucy
|
|
|
16
15
|
@@layouts = Layouts.new
|
|
17
16
|
@@admin_username = 'admin'
|
|
18
17
|
@@admin_password = 'admin'
|
|
19
|
-
@@merchant_account_time_zone = 'Eastern Time (US & Canada)'
|
|
20
18
|
end
|
|
21
19
|
|
|
22
20
|
end
|
data/lib/saucy/engine.rb
CHANGED
data/lib/saucy/fake_braintree.rb
CHANGED
|
@@ -102,7 +102,7 @@ ShamRack.at("www.braintreegateway.com", 443).sinatra do
|
|
|
102
102
|
subscription["transactions"] = []
|
|
103
103
|
subscription["add_ons"] = []
|
|
104
104
|
subscription["discounts"] = []
|
|
105
|
-
subscription["next_billing_date"] = 1.month.from_now
|
|
105
|
+
subscription["next_billing_date"] = 1.month.from_now
|
|
106
106
|
subscription["status"] = Braintree::Subscription::Status::Active
|
|
107
107
|
FakeBraintree.subscriptions[subscription["id"]] = subscription
|
|
108
108
|
[201, { "Content-Encoding" => "gzip" }, ActiveSupport::Gzip.compress(subscription.to_xml(:root => 'subscription'))]
|
|
@@ -6,13 +6,8 @@
|
|
|
6
6
|
# project_path(@project), because the account can be inferred from the project.
|
|
7
7
|
module Saucy
|
|
8
8
|
module MapperExtensions
|
|
9
|
-
def initialize(*args)
|
|
10
|
-
@through_scope = []
|
|
11
|
-
super
|
|
12
|
-
end
|
|
13
|
-
|
|
14
9
|
def through(parent, &block)
|
|
15
|
-
@through_scope << parent
|
|
10
|
+
(@through_scope ||= []) << parent
|
|
16
11
|
resources(parent, :only => [], &block)
|
|
17
12
|
@through_scope.pop
|
|
18
13
|
end
|
|
@@ -82,7 +77,7 @@ end
|
|
|
82
77
|
ActionDispatch::Routing::Mapper::Base.class_eval do
|
|
83
78
|
def match_with_through(path, options=nil)
|
|
84
79
|
match_without_through(path, options)
|
|
85
|
-
|
|
80
|
+
if @through_scope.present?
|
|
86
81
|
route = @set.routes.last
|
|
87
82
|
@set.named_routes.add_through_alias(route, @through_scope) if route.name
|
|
88
83
|
end
|
data/lib/saucy/subscription.rb
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require 'airbrake'
|
|
2
|
-
|
|
3
1
|
module Saucy
|
|
4
2
|
module Subscription
|
|
5
3
|
extend ActiveSupport::Concern
|
|
@@ -88,10 +86,9 @@ module Saucy
|
|
|
88
86
|
end
|
|
89
87
|
|
|
90
88
|
def update_subscription_cache!
|
|
91
|
-
zone = ActiveSupport::TimeZone[Saucy::Configuration.merchant_account_time_zone]
|
|
92
89
|
flush_cache :subscription
|
|
93
90
|
update_attribute(:subscription_status, subscription.status)
|
|
94
|
-
update_attribute(:next_billing_date,
|
|
91
|
+
update_attribute(:next_billing_date, subscription.next_billing_date)
|
|
95
92
|
end
|
|
96
93
|
|
|
97
94
|
def changing_plan?(attributes)
|
|
@@ -113,20 +110,7 @@ module Saucy
|
|
|
113
110
|
if valid?
|
|
114
111
|
result = Braintree::Customer.update(customer_token, customer_attributes)
|
|
115
112
|
handle_customer_result(result)
|
|
116
|
-
if !result.success?
|
|
117
|
-
Airbrake.notify(
|
|
118
|
-
:error_class => "Customer update",
|
|
119
|
-
:error_message => "Customer update failed",
|
|
120
|
-
:parameters => { :customer_token => customer_token, :customer_attributes => customer_attributes }
|
|
121
|
-
)
|
|
122
|
-
end
|
|
123
113
|
result.success?
|
|
124
|
-
else
|
|
125
|
-
Airbrake.notify(
|
|
126
|
-
:error_class => "Subscription Validation",
|
|
127
|
-
:error_message => "Customer failed validation",
|
|
128
|
-
:parameters => customer_attributes
|
|
129
|
-
)
|
|
130
114
|
end
|
|
131
115
|
end
|
|
132
116
|
|
|
@@ -191,11 +175,6 @@ module Saucy
|
|
|
191
175
|
end
|
|
192
176
|
|
|
193
177
|
def handle_errors(result, remote_errors)
|
|
194
|
-
Airbrake.notify(
|
|
195
|
-
:error_class => "handle_errors",
|
|
196
|
-
:error_message => "handle_errors",
|
|
197
|
-
:parameters => { :result => result, :remote_errors => remote_errors }
|
|
198
|
-
)
|
|
199
178
|
if result && result.status == "processor_declined"
|
|
200
179
|
errors[:card_number] << "was denied by the payment processor with the message: #{result.processor_response_text}"
|
|
201
180
|
elsif result && result.status == "gateway_rejected"
|
|
@@ -218,16 +197,10 @@ module Saucy
|
|
|
218
197
|
def create_subscription
|
|
219
198
|
result = Braintree::Subscription.create(subscription_attributes)
|
|
220
199
|
if result.success?
|
|
221
|
-
zone = ActiveSupport::TimeZone[Saucy::Configuration.merchant_account_time_zone]
|
|
222
200
|
self.subscription_token = result.subscription.id
|
|
223
|
-
self.next_billing_date =
|
|
201
|
+
self.next_billing_date = result.subscription.next_billing_date
|
|
224
202
|
self.subscription_status = result.subscription.status
|
|
225
203
|
else
|
|
226
|
-
Airbrake.notify(
|
|
227
|
-
:error_class => "Subscription creation",
|
|
228
|
-
:error_message => "Subscription creation failed",
|
|
229
|
-
:parameters => subscription_attributes
|
|
230
|
-
)
|
|
231
204
|
false
|
|
232
205
|
end
|
|
233
206
|
end
|
|
@@ -251,9 +224,8 @@ module Saucy
|
|
|
251
224
|
def update_subscriptions!
|
|
252
225
|
recently_billed = where("next_billing_date <= ?", Time.now)
|
|
253
226
|
recently_billed.each do |account|
|
|
254
|
-
zone = ActiveSupport::TimeZone[Saucy::Configuration.merchant_account_time_zone]
|
|
255
227
|
account.subscription_status = account.subscription.status
|
|
256
|
-
account.next_billing_date =
|
|
228
|
+
account.next_billing_date = account.subscription.next_billing_date
|
|
257
229
|
account.save!
|
|
258
230
|
if account.past_due?
|
|
259
231
|
BillingMailer.problem(account, account.subscription.transactions.last).deliver!
|
data/spec/environment.rb
CHANGED
|
@@ -31,11 +31,11 @@ module Testapp
|
|
|
31
31
|
class Application < Rails::Application
|
|
32
32
|
config.action_mailer.default_url_options = { :host => 'localhost' }
|
|
33
33
|
config.encoding = "utf-8"
|
|
34
|
-
config.paths
|
|
35
|
-
config.paths
|
|
36
|
-
config.paths
|
|
37
|
-
config.paths
|
|
38
|
-
config.paths
|
|
34
|
+
config.paths['config/database'] = "spec/scaffold/config/database.yml"
|
|
35
|
+
config.paths['app/models'] << "lib/generators/saucy/install/templates/models"
|
|
36
|
+
config.paths['config/routes'] << "spec/scaffold/config/routes.rb"
|
|
37
|
+
config.paths['app/views'] << "spec/scaffold/views"
|
|
38
|
+
config.paths['log'] = "tmp/log"
|
|
39
39
|
config.cache_classes = true
|
|
40
40
|
config.whiny_nils = true
|
|
41
41
|
config.consider_all_requests_local = true
|
|
@@ -48,6 +48,7 @@ module Testapp
|
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
Testapp::Application.initialize!
|
|
51
|
+
ActionController::Base.send :include, Rails.application.routes.url_helpers
|
|
51
52
|
|
|
52
53
|
require "./lib/generators/saucy/features/templates/factories"
|
|
53
54
|
require "./lib/generators/saucy/install/templates/create_saucy_tables"
|
|
@@ -122,9 +122,8 @@ describe Account, "with a paid plan" do
|
|
|
122
122
|
subject.subscription.should_not be_nil
|
|
123
123
|
end
|
|
124
124
|
|
|
125
|
-
it "has a next_billing_date
|
|
126
|
-
|
|
127
|
-
subject.next_billing_date.should == Time.parse("Sun, 16 Oct 2011 00:00:00 EDT -04:00")
|
|
125
|
+
it "has a next_billing_date" do
|
|
126
|
+
subject.next_billing_date.should_not be_nil
|
|
128
127
|
end
|
|
129
128
|
|
|
130
129
|
it "has an active subscription status" do
|
|
@@ -295,18 +294,15 @@ describe Account, "with a paid subscription" do
|
|
|
295
294
|
:plan => Factory(:paid_plan))
|
|
296
295
|
end
|
|
297
296
|
|
|
298
|
-
let(:merchant_time_zone) { ActiveSupport::TimeZone[Saucy::Configuration.merchant_account_time_zone] }
|
|
299
|
-
|
|
300
297
|
it "gets marked as past due and updates its next_billing_date when subscriptions are updated and it has been rejected by the gateway" do
|
|
301
|
-
next_billing_date_string = 2.months.from_now.to_s(:braintree_date)
|
|
302
298
|
subscription = FakeBraintree.subscriptions[subject.subscription_token]
|
|
303
299
|
subscription["status"] = Braintree::Subscription::Status::PastDue
|
|
304
|
-
subscription["next_billing_date"] =
|
|
300
|
+
subscription["next_billing_date"] = 2.months.from_now
|
|
305
301
|
|
|
306
302
|
Timecop.travel(subject.next_billing_date + 1.day) do
|
|
307
303
|
Account.update_subscriptions!
|
|
308
304
|
subject.reload.subscription_status.should == Braintree::Subscription::Status::PastDue
|
|
309
|
-
subject.next_billing_date.should ==
|
|
305
|
+
subject.next_billing_date.to_s.should == subscription["next_billing_date"].to_s
|
|
310
306
|
subject.past_due?.should be
|
|
311
307
|
end
|
|
312
308
|
end
|
|
@@ -316,7 +312,7 @@ describe Account, "with a paid subscription" do
|
|
|
316
312
|
|
|
317
313
|
before do
|
|
318
314
|
subscription["status"] = Braintree::Subscription::Status::PastDue
|
|
319
|
-
subscription["next_billing_date"] = 2.months.from_now
|
|
315
|
+
subscription["next_billing_date"] = 2.months.from_now
|
|
320
316
|
FakeBraintree.transaction = { :status => Braintree::Transaction::Status::Failed,
|
|
321
317
|
:subscription_id => subject.subscription_token }
|
|
322
318
|
subscription["transactions"] = [FakeBraintree.generated_transaction]
|
|
@@ -343,57 +339,12 @@ describe Account, "with a paid subscription" do
|
|
|
343
339
|
end
|
|
344
340
|
end
|
|
345
341
|
|
|
346
|
-
context "with a merchant account timezone different from the system timezone" do
|
|
347
|
-
def build_subscription(account)
|
|
348
|
-
subscription = FakeBraintree.subscriptions[account.subscription_token]
|
|
349
|
-
subscription["status"] = Braintree::Subscription::Status::Active
|
|
350
|
-
subscription["transactions"] = [FakeBraintree.generated_transaction]
|
|
351
|
-
subscription
|
|
352
|
-
end
|
|
353
|
-
|
|
354
|
-
before do
|
|
355
|
-
@old_env_tz = ENV['TZ']
|
|
356
|
-
ENV['TZ'] = "Europe/Paris"
|
|
357
|
-
|
|
358
|
-
Saucy::Configuration.merchant_account_time_zone = "Eastern Time (US & Canada)"
|
|
359
|
-
subject.next_billing_date = "2011-08-15"
|
|
360
|
-
subject.save!
|
|
361
|
-
|
|
362
|
-
subscription = build_subscription(subject)
|
|
363
|
-
subscription["next_billing_date"] = "2011-09-15"
|
|
364
|
-
|
|
365
|
-
Time.stubs(:now => Time.parse("2011-08-16 02:00 -0000"))
|
|
366
|
-
Account.update_subscriptions!
|
|
367
|
-
ActionMailer::Base.deliveries.clear
|
|
368
|
-
|
|
369
|
-
subject.reload.next_billing_date.should == Time.parse("2011-09-15 00:00 -0400")
|
|
370
|
-
end
|
|
371
|
-
|
|
372
|
-
after do
|
|
373
|
-
ENV['TZ'] = @old_env_tz
|
|
374
|
-
end
|
|
375
|
-
|
|
376
|
-
it "does not update accounts if their billing date hasn't elapsed from the merchant account's perspective" do
|
|
377
|
-
Time.stubs(:now => Time.parse("2011-09-15 02:00 -0000"))
|
|
378
|
-
Account.update_subscriptions!
|
|
379
|
-
ActionMailer::Base.deliveries.should be_empty
|
|
380
|
-
end
|
|
381
|
-
|
|
382
|
-
it "does update accounts if their billing date has elapsed from the merchant account's perspective" do
|
|
383
|
-
Time.stubs(:now => Time.parse("2011-09-16 02:00 -0000"))
|
|
384
|
-
Account.update_subscriptions!
|
|
385
|
-
ActionMailer::Base.deliveries.should_not be_empty
|
|
386
|
-
end
|
|
387
|
-
end
|
|
388
|
-
|
|
389
342
|
context "and an active subscription due 2 months from now" do
|
|
390
343
|
let(:subscription) { FakeBraintree.subscriptions[subject.subscription_token] }
|
|
391
|
-
let(:next_billing_date_string) { 2.months.from_now.to_s(:braintree_date) }
|
|
392
|
-
let(:zone) { ActiveSupport::TimeZone[Saucy::Configuration.merchant_account_time_zone] }
|
|
393
344
|
|
|
394
345
|
before do
|
|
395
346
|
subscription["status"] = Braintree::Subscription::Status::Active
|
|
396
|
-
subscription["next_billing_date"] =
|
|
347
|
+
subscription["next_billing_date"] = 2.months.from_now
|
|
397
348
|
FakeBraintree.transaction = { :status => Braintree::Transaction::Status::Settled,
|
|
398
349
|
:subscription_id => subject.subscription_token }
|
|
399
350
|
subscription["transactions"] = [FakeBraintree.generated_transaction]
|
|
@@ -403,7 +354,7 @@ describe Account, "with a paid subscription" do
|
|
|
403
354
|
Timecop.travel(subject.next_billing_date + 1.day) do
|
|
404
355
|
Account.update_subscriptions!
|
|
405
356
|
subject.reload.subscription_status.should == Braintree::Subscription::Status::Active
|
|
406
|
-
subject.next_billing_date.should ==
|
|
357
|
+
subject.next_billing_date.to_s.should == subscription["next_billing_date"].to_s
|
|
407
358
|
end
|
|
408
359
|
end
|
|
409
360
|
|
|
@@ -464,7 +415,7 @@ describe Account, "with a paid subscription that is past due" do
|
|
|
464
415
|
before do
|
|
465
416
|
subscription = FakeBraintree.subscriptions[subject.subscription_token]
|
|
466
417
|
subscription["status"] = Braintree::Subscription::Status::PastDue
|
|
467
|
-
subscription["next_billing_date"] = 2.months.from_now
|
|
418
|
+
subscription["next_billing_date"] = 2.months.from_now
|
|
468
419
|
|
|
469
420
|
Timecop.travel(subject.next_billing_date + 1.day) do
|
|
470
421
|
Account.update_subscriptions!
|
|
@@ -472,13 +423,10 @@ describe Account, "with a paid subscription that is past due" do
|
|
|
472
423
|
subject.reload
|
|
473
424
|
end
|
|
474
425
|
|
|
475
|
-
let(:zone) { ActiveSupport::TimeZone[Saucy::Configuration.merchant_account_time_zone] }
|
|
476
|
-
|
|
477
426
|
it "retries the subscription charge and updates the subscription when the billing information is correctly updated" do
|
|
478
|
-
next_billing_date_string = 1.day.from_now.to_s(:braintree_date)
|
|
479
427
|
subscription = FakeBraintree.subscriptions[subject.subscription_token]
|
|
480
428
|
subscription["status"] = Braintree::Subscription::Status::Active
|
|
481
|
-
subscription["next_billing_date"] =
|
|
429
|
+
subscription["next_billing_date"] = 2.months.from_now
|
|
482
430
|
FakeBraintree.transaction = { :status => Braintree::Transaction::Status::Settled,
|
|
483
431
|
:subscription_id => subject.subscription_token }
|
|
484
432
|
transaction = FakeBraintree.generated_transaction
|
|
@@ -496,14 +444,13 @@ describe Account, "with a paid subscription that is past due" do
|
|
|
496
444
|
:expiration_year => 2012).should be
|
|
497
445
|
|
|
498
446
|
subject.reload.subscription_status.should == Braintree::Subscription::Status::Active
|
|
499
|
-
subject.next_billing_date.should ==
|
|
447
|
+
subject.next_billing_date.to_s.should == subscription["next_billing_date"].to_s
|
|
500
448
|
end
|
|
501
449
|
|
|
502
450
|
it "retries the subscription charge and updates the subscription when the payment processing fails" do
|
|
503
|
-
next_billing_date_string = 2.months.from_now.to_s(:braintree_date)
|
|
504
451
|
subscription = FakeBraintree.subscriptions[subject.subscription_token]
|
|
505
452
|
subscription["status"] = Braintree::Subscription::Status::PastDue
|
|
506
|
-
subscription["next_billing_date"] =
|
|
453
|
+
subscription["next_billing_date"] = 1.day.from_now
|
|
507
454
|
FakeBraintree.transaction = { :status => Braintree::Transaction::Status::Failed,
|
|
508
455
|
:subscription_id => subject.subscription_token }
|
|
509
456
|
transaction = FakeBraintree.generated_transaction
|
|
@@ -522,14 +469,13 @@ describe Account, "with a paid subscription that is past due" do
|
|
|
522
469
|
|
|
523
470
|
subject.errors[:card_number].should include("was denied by the payment processor with the message: no good")
|
|
524
471
|
subject.reload.subscription_status.should == Braintree::Subscription::Status::PastDue
|
|
525
|
-
subject.next_billing_date.should ==
|
|
472
|
+
subject.next_billing_date.to_s.should == subscription["next_billing_date"].to_s
|
|
526
473
|
end
|
|
527
474
|
|
|
528
475
|
it "retries the subscription charge and updates the subscription when the settlement fails" do
|
|
529
|
-
next_billing_date_string = 1.day.from_now.to_s(:braintree_date)
|
|
530
476
|
subscription = FakeBraintree.subscriptions[subject.subscription_token]
|
|
531
477
|
subscription["status"] = Braintree::Subscription::Status::PastDue
|
|
532
|
-
subscription["next_billing_date"] =
|
|
478
|
+
subscription["next_billing_date"] = 1.day.from_now
|
|
533
479
|
FakeBraintree.transaction = { :status => Braintree::Transaction::Status::Failed,
|
|
534
480
|
:subscription_id => subject.subscription_token }
|
|
535
481
|
transaction = FakeBraintree.generated_transaction
|
|
@@ -548,7 +494,7 @@ describe Account, "with a paid subscription that is past due" do
|
|
|
548
494
|
|
|
549
495
|
subject.errors[:card_number].should include("no good")
|
|
550
496
|
subject.reload.subscription_status.should == Braintree::Subscription::Status::PastDue
|
|
551
|
-
subject.next_billing_date.should ==
|
|
497
|
+
subject.next_billing_date.to_s.should == subscription["next_billing_date"].to_s
|
|
552
498
|
end
|
|
553
499
|
end
|
|
554
500
|
|
|
@@ -36,18 +36,4 @@ describe Saucy::Configuration do
|
|
|
36
36
|
subject.support_email_address = old_address
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
|
-
|
|
40
|
-
it "can assign a merchant_account_time_zone" do
|
|
41
|
-
old_merchant_account_time_zone = subject.merchant_account_time_zone
|
|
42
|
-
begin
|
|
43
|
-
subject.merchant_account_time_zone = "International Date Line West"
|
|
44
|
-
subject.merchant_account_time_zone.should == "International Date Line West"
|
|
45
|
-
ensure
|
|
46
|
-
subject.merchant_account_time_zone = old_merchant_account_time_zone
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
it "defaults merchant_account_time_zone to 'Eastern Time (US & Canada)'" do
|
|
51
|
-
subject.merchant_account_time_zone.should == "Eastern Time (US & Canada)"
|
|
52
|
-
end
|
|
53
39
|
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
ENV["RAILS_ENV"] ||= 'test'
|
|
3
3
|
|
|
4
4
|
if File.exist?("config/environment.rb")
|
|
5
|
-
require "config/environment"
|
|
5
|
+
require "./config/environment"
|
|
6
6
|
else
|
|
7
7
|
require File.expand_path("../environment", __FILE__)
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
require 'rspec/rails'
|
|
11
|
-
require 'shoulda'
|
|
11
|
+
require 'shoulda/matchers'
|
|
12
12
|
require 'timecop'
|
|
13
13
|
|
|
14
14
|
# Requires supporting ruby files with custom matchers and macros, etc,
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: saucy
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
hash:
|
|
4
|
+
hash: 55
|
|
5
5
|
prerelease:
|
|
6
6
|
segments:
|
|
7
7
|
- 0
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
version: 0.
|
|
8
|
+
- 11
|
|
9
|
+
- 2
|
|
10
|
+
version: 0.11.2
|
|
11
11
|
platform: ruby
|
|
12
12
|
authors:
|
|
13
13
|
- thoughtbot, inc.
|
|
@@ -20,7 +20,7 @@ autorequire:
|
|
|
20
20
|
bindir: bin
|
|
21
21
|
cert_chain: []
|
|
22
22
|
|
|
23
|
-
date: 2011-
|
|
23
|
+
date: 2011-09-12 00:00:00 Z
|
|
24
24
|
dependencies:
|
|
25
25
|
- !ruby/object:Gem::Dependency
|
|
26
26
|
name: clearance
|
|
@@ -117,26 +117,10 @@ dependencies:
|
|
|
117
117
|
version: 1.1.2
|
|
118
118
|
type: :runtime
|
|
119
119
|
version_requirements: *id006
|
|
120
|
-
- !ruby/object:Gem::Dependency
|
|
121
|
-
name: airbrake
|
|
122
|
-
prerelease: false
|
|
123
|
-
requirement: &id007 !ruby/object:Gem::Requirement
|
|
124
|
-
none: false
|
|
125
|
-
requirements:
|
|
126
|
-
- - ">="
|
|
127
|
-
- !ruby/object:Gem::Version
|
|
128
|
-
hash: 15
|
|
129
|
-
segments:
|
|
130
|
-
- 3
|
|
131
|
-
- 0
|
|
132
|
-
- 4
|
|
133
|
-
version: 3.0.4
|
|
134
|
-
type: :runtime
|
|
135
|
-
version_requirements: *id007
|
|
136
120
|
- !ruby/object:Gem::Dependency
|
|
137
121
|
name: aruba
|
|
138
122
|
prerelease: false
|
|
139
|
-
requirement: &
|
|
123
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
|
140
124
|
none: false
|
|
141
125
|
requirements:
|
|
142
126
|
- - "="
|
|
@@ -148,7 +132,7 @@ dependencies:
|
|
|
148
132
|
- 6
|
|
149
133
|
version: 0.2.6
|
|
150
134
|
type: :development
|
|
151
|
-
version_requirements: *
|
|
135
|
+
version_requirements: *id007
|
|
152
136
|
description: Clearance-based Rails engine for Software as a Service (Saas) that provides account and project management
|
|
153
137
|
email: support@thoughtbot.com
|
|
154
138
|
executables: []
|
|
@@ -358,7 +342,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
358
342
|
requirements: []
|
|
359
343
|
|
|
360
344
|
rubyforge_project:
|
|
361
|
-
rubygems_version: 1.8.
|
|
345
|
+
rubygems_version: 1.8.10
|
|
362
346
|
signing_key:
|
|
363
347
|
specification_version: 3
|
|
364
348
|
summary: Clearance-based Rails engine for SaaS
|