saucy 0.13.3 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +4 -0
- data/app/controllers/billings_controller.rb +7 -0
- data/app/models/signup.rb +9 -2
- data/app/views/billings/_form.html.erb +12 -2
- data/features/run_features.feature +1 -0
- data/lib/generators/saucy/features/templates/factories.rb +5 -0
- data/lib/generators/saucy/features/templates/features/manage_billing.feature +41 -26
- data/lib/generators/saucy/features/templates/features/manage_plan.feature +16 -5
- data/lib/generators/saucy/features/templates/features/sign_up_paid.feature +18 -0
- data/lib/generators/saucy/features/templates/features/trial_plans.feature +0 -9
- data/lib/generators/saucy/features/templates/step_definitions/country_steps.rb +8 -0
- data/lib/saucy/subscription.rb +38 -13
- data/spec/models/subscription_spec.rb +105 -91
- metadata +4 -53
data/CHANGELOG.md
CHANGED
@@ -12,6 +12,13 @@ class BillingsController < ApplicationController
|
|
12
12
|
@account.billing_email = @account.customer.email
|
13
13
|
@account.expiration_month = @account.credit_card.expiration_month
|
14
14
|
@account.expiration_year = @account.credit_card.expiration_year
|
15
|
+
|
16
|
+
@account.street_address = @account.billing_address.street_address
|
17
|
+
@account.extended_address = @account.billing_address.extended_address
|
18
|
+
@account.locality = @account.billing_address.locality
|
19
|
+
@account.region = @account.billing_address.region
|
20
|
+
@account.postal_code = @account.billing_address.postal_code
|
21
|
+
@account.country_name = @account.billing_address.country_name
|
15
22
|
end
|
16
23
|
|
17
24
|
def update
|
data/app/models/signup.rb
CHANGED
@@ -13,7 +13,13 @@ class Signup
|
|
13
13
|
:expiration_month => :expiration_month,
|
14
14
|
:expiration_year => :expiration_year,
|
15
15
|
:verification_code => :verification_code,
|
16
|
-
:plan => :plan
|
16
|
+
:plan => :plan,
|
17
|
+
:street_address => :street_address,
|
18
|
+
:extended_address => :extended_address,
|
19
|
+
:locality => :locality,
|
20
|
+
:region => :region,
|
21
|
+
:postal_code => :postal_code,
|
22
|
+
:country_name => :country_name
|
17
23
|
},
|
18
24
|
:user => {
|
19
25
|
:email => :email,
|
@@ -22,7 +28,8 @@ class Signup
|
|
22
28
|
}.freeze
|
23
29
|
|
24
30
|
attr_accessor :billing_email, :password, :cardholder_name, :email,
|
25
|
-
:card_number, :expiration_month, :expiration_year, :plan, :verification_code, :coupon
|
31
|
+
:card_number, :expiration_month, :expiration_year, :plan, :verification_code, :coupon,
|
32
|
+
:street_address, :extended_address, :locality, :region, :postal_code, :country_name
|
26
33
|
|
27
34
|
def initialize(attributes = {})
|
28
35
|
if attributes
|
@@ -1,8 +1,18 @@
|
|
1
1
|
<%= form.inputs do %>
|
2
|
-
<%= form.input :cardholder_name, :required => true %>
|
3
|
-
<%= form.input :billing_email, :required => true, :hint => "We'll send receipts and billing issues to this address." %>
|
4
2
|
<%= form.input :card_number, :required => true, :input_html => { :autocomplete => "off" } %>
|
5
3
|
<%= form.input :verification_code, :required => true, :input_html => { :autocomplete => "off" } %>
|
6
4
|
<%= form.input :expiration_month, :collection => [['January', '01'], ['February', '02'], ['March', '03'], ['April', '04'], ['May', '05'], ['June', '06'], ['July', '07'], ['August', '08'], ['September', '09'], ['October', '10'], ['November', '11'], ['December', '12']], :required => true %>
|
7
5
|
<%= form.input :expiration_year, :collection => (Date.today.year..(Date.today.year+10)).to_a, :required => true %>
|
6
|
+
<%= form.input :cardholder_name, :required => true %>
|
7
|
+
<%= form.input :billing_email, :required => true, :hint => "We'll send receipts and billing issues to this address." %>
|
8
|
+
|
9
|
+
<%= form.input :street_address, :label => "Address Line 1", :required => true %>
|
10
|
+
<%= form.input :extended_address, :label => "Address Line 2", :required => true %>
|
11
|
+
<%= form.input :locality, :label => "City", :required => true %>
|
12
|
+
<%= form.input :region, :label => "State or Province", :required => true %>
|
13
|
+
<%= form.input :postal_code, :label => "ZIP or Postal Code", :required => true %>
|
14
|
+
<%= form.input :country_name, :label => "Country",
|
15
|
+
:required => true,
|
16
|
+
:collection => ["United States of America", "Canada", "---",
|
17
|
+
*Braintree::Address::CountryNames.map(&:first)] %>
|
8
18
|
<% end -%>
|
@@ -20,6 +20,7 @@ Feature: generate a saucy application and run rake
|
|
20
20
|
gem "launchy"
|
21
21
|
gem "timecop"
|
22
22
|
gem "jquery-rails"
|
23
|
+
gem "minitest", "~> 2.6.1", :platforms => :ruby_19
|
23
24
|
"""
|
24
25
|
When I add the "saucy" gem from this project as a dependency
|
25
26
|
And I successfully run `bundle install`
|
@@ -25,6 +25,11 @@ Factory.define :paid_account, :parent => :account do |f|
|
|
25
25
|
f.verification_code { "123" }
|
26
26
|
f.expiration_month { 5 }
|
27
27
|
f.expiration_year { 2012 }
|
28
|
+
f.street_address { "1 Robo Lane" }
|
29
|
+
f.locality { "Boston" }
|
30
|
+
f.region { "MA" }
|
31
|
+
f.postal_code { "02108" }
|
32
|
+
f.country_name { "United States of America" }
|
28
33
|
f.association :plan, :factory => :paid_plan
|
29
34
|
end
|
30
35
|
|
@@ -3,12 +3,14 @@ Feature: Manage Billing
|
|
3
3
|
I want to be able to manage my billing information
|
4
4
|
So that my account can stay up to date and in good standing
|
5
5
|
|
6
|
-
|
6
|
+
Background:
|
7
7
|
Given a paid plan exists with a name of "Paid"
|
8
8
|
And the following account exists:
|
9
|
-
| name | keyword | plan | cardholder_name | billing_email | card_number | verification_code | expiration_month | expiration_year |
|
10
|
-
| Test | test | name: Paid | Joe Smith | jsmith@example.com | 4111111111115555 | 122 | 01 | 2015 |
|
11
|
-
|
9
|
+
| name | keyword | plan | cardholder_name | billing_email | card_number | verification_code | expiration_month | expiration_year | street_address | extended_address | locality | region | postal_code | country_name |
|
10
|
+
| Test | test | name: Paid | Joe Smith | jsmith@example.com | 4111111111115555 | 122 | 01 | 2015 | 1 Robo Lane | Suite 333 | Beverly Hills | CA | 90210 | United States of America |
|
11
|
+
|
12
|
+
Scenario: Update the billing information on an account with a paid plan
|
13
|
+
Given I have signed in with "joe@example.com"
|
12
14
|
And "joe@example.com" is an admin of the "Test" account
|
13
15
|
When I go to the billing page for the "Test" account
|
14
16
|
Then I should see "card ending in 5555"
|
@@ -21,23 +23,39 @@ Feature: Manage Billing
|
|
21
23
|
And the "Verification code" field should have nothing in it
|
22
24
|
And the "Expiration month" field should contain "01"
|
23
25
|
And the "Expiration year" field should contain "2015"
|
26
|
+
And the "Address Line 1" field should contain "1 Robo Lane"
|
27
|
+
And the "Address Line 2" field should contain "Suite 333"
|
28
|
+
And the "City" field should contain "Beverly Hills"
|
29
|
+
And the "State or Province" field should contain "CA"
|
30
|
+
And the "ZIP or Postal Code" field should contain "90210"
|
31
|
+
And the "Country" field should contain "United States of America"
|
24
32
|
|
25
|
-
|
33
|
+
When I fill in "Cardholder name" with "Ralph Robot"
|
26
34
|
And I fill in "Billing email" with "accounting@example.com"
|
27
35
|
And I fill in "Card number" with "4111111111111111"
|
28
36
|
And I fill in "Verification code" with "123"
|
29
37
|
And I select "March" from "Expiration month"
|
30
38
|
And I select "2020" from "Expiration year"
|
39
|
+
And I fill in "Address Line 1" with "41 Winter St"
|
40
|
+
And I fill in "Address Line 2" with "Floor 7"
|
41
|
+
And I fill in "City" with "Boston"
|
42
|
+
And I fill in "State or Province" with "MA"
|
43
|
+
And I fill in "ZIP or Postal Code" with "02108"
|
44
|
+
And I select "Uganda" from "Country"
|
31
45
|
And I press "Update"
|
32
46
|
Then I should see "updated successfully"
|
33
|
-
|
47
|
+
And I should see "card ending in 1111"
|
48
|
+
|
49
|
+
When I follow "Change"
|
50
|
+
Then the "Address Line 1" field should contain "41 Winter St"
|
51
|
+
And the "Address Line 2" field should contain "Floor 7"
|
52
|
+
And the "City" field should contain "Boston"
|
53
|
+
And the "State or Province" field should contain "MA"
|
54
|
+
And the "ZIP or Postal Code" field should contain "02108"
|
55
|
+
And the "Country" field should contain "Uganda"
|
34
56
|
|
35
57
|
Scenario: Be forced to update the billing information on an account with a paid plan that is past due
|
36
|
-
Given
|
37
|
-
And the following account exists:
|
38
|
-
| name | keyword | plan | cardholder_name | billing_email | card_number | verification_code | expiration_month | expiration_year |
|
39
|
-
| Test | test | name: Paid | Joe Smith | jsmith@example.com | 4111111111115555 | 122 | 01 | 2015 |
|
40
|
-
And the "Test" account is past due
|
58
|
+
Given the "Test" account is past due
|
41
59
|
And I have signed in with "joe@example.com"
|
42
60
|
And "joe@example.com" is an admin of the "Test" account
|
43
61
|
When I go to the settings page for the "Test" account
|
@@ -45,11 +63,7 @@ Feature: Manage Billing
|
|
45
63
|
And I should see "There was an issue processing the credit card you have on file. Please update your credit card information."
|
46
64
|
|
47
65
|
Scenario: Be told to have an admin update the billing information on an account with a paid plan that is past due
|
48
|
-
Given
|
49
|
-
And the following account exists:
|
50
|
-
| name | keyword | plan | cardholder_name | billing_email | card_number | verification_code | expiration_month | expiration_year |
|
51
|
-
| Test | test | name: Paid | Joe Smith | jsmith@example.com | 4111111111115555 | 122 | 01 | 2015 |
|
52
|
-
And the "Test" account is past due
|
66
|
+
Given the "Test" account is past due
|
53
67
|
And the following projects exist:
|
54
68
|
| name | account |
|
55
69
|
| Project | name: Test |
|
@@ -64,11 +78,7 @@ Feature: Manage Billing
|
|
64
78
|
Then I should be on the billing page for the "Test" account
|
65
79
|
|
66
80
|
Scenario: View past credit card charges
|
67
|
-
Given
|
68
|
-
And the following account exists:
|
69
|
-
| name | keyword | plan | cardholder_name | billing_email | card_number | verification_code | expiration_month | expiration_year |
|
70
|
-
| Test | test | name: Paid | Joe Smith | jsmith@example.com | 4111111111115555 | 122 | 01 | 2015 |
|
71
|
-
And the following transaction exist for the "Test" account:
|
81
|
+
Given the following transaction exist for the "Test" account:
|
72
82
|
| status | amount | created_at |
|
73
83
|
| Settled | 20.00 | July 1, 2010 |
|
74
84
|
| Settled | 5.00 | August 1, 2010 |
|
@@ -80,14 +90,19 @@ Feature: Manage Billing
|
|
80
90
|
And I should see "08/01/10 $5"
|
81
91
|
|
82
92
|
Scenario: Navigate back to the main settings page
|
83
|
-
Given
|
84
|
-
And the following account exists:
|
85
|
-
| name | keyword | plan | cardholder_name | billing_email | card_number | verification_code | expiration_month | expiration_year |
|
86
|
-
| Test | test | name: Paid | Joe Smith | jsmith@example.com | 4111111111115555 | 122 | 01 | 2015 |
|
87
|
-
And I have signed in with "joe@example.com"
|
93
|
+
Given I have signed in with "joe@example.com"
|
88
94
|
And "joe@example.com" is an admin of the "Test" account
|
89
95
|
When I go to the billing page for the "Test" account
|
90
96
|
And I follow "Change"
|
91
97
|
And I follow "Billing"
|
92
98
|
And I follow "Account Info"
|
93
99
|
Then I should be on the settings page for the "Test" account
|
100
|
+
|
101
|
+
Scenario: Billing countries
|
102
|
+
Given I have signed in with "joe@example.com"
|
103
|
+
And "joe@example.com" is an admin of the "Test" account
|
104
|
+
When I go to the billing page for the "Test" account
|
105
|
+
And I follow "Change"
|
106
|
+
Then I should see all the Braintree countries in the country select with the following at the top:
|
107
|
+
| United States of America |
|
108
|
+
| Canada |
|
@@ -6,7 +6,7 @@ Feature: Manage Plan
|
|
6
6
|
Scenario: Change the plan to another paid plan on an account with a paid plan
|
7
7
|
Given a paid plan exists with a name of "Basic"
|
8
8
|
And a paid plan exists with a name of "Premium"
|
9
|
-
And the following account exists:
|
9
|
+
And the following paid account exists:
|
10
10
|
| name | keyword | plan | cardholder_name | billing_email | card_number | verification_code | expiration_month | expiration_year |
|
11
11
|
| Test | test | name: Basic | Joe Smith | jsmith@example.com | 4111111111115555 | 122 | 01 | 2015 |
|
12
12
|
And I have signed in with "joe@example.com"
|
@@ -37,13 +37,18 @@ Feature: Manage Plan
|
|
37
37
|
Then I should see "Upgrade Your Plan"
|
38
38
|
When I choose the "Basic" plan
|
39
39
|
Then I should see "Billing Information"
|
40
|
-
And I should not see "No thanks, just delete my account"
|
41
40
|
And I fill in "Cardholder name" with "Ralph Robot"
|
42
41
|
And I fill in "Billing email" with "accounting@example.com"
|
43
42
|
And I fill in "Card number" with "4111111111111111"
|
44
43
|
And I fill in "Verification code" with "123"
|
45
44
|
And I select "March" from "Expiration month"
|
46
45
|
And I select "2020" from "Expiration year"
|
46
|
+
And I fill in "Address Line 1" with "41 Winter St"
|
47
|
+
And I fill in "Address Line 2" with "Floor 7"
|
48
|
+
And I fill in "City" with "Boston"
|
49
|
+
And I fill in "State or Province" with "MA"
|
50
|
+
And I fill in "ZIP or Postal Code" with "02108"
|
51
|
+
And I select "United States of America" from "Country"
|
47
52
|
When I press "Upgrade"
|
48
53
|
Then I should see "Plan changed successfully"
|
49
54
|
And I should see "Basic"
|
@@ -71,6 +76,12 @@ Feature: Manage Plan
|
|
71
76
|
And I fill in "Verification code" with "123"
|
72
77
|
And I select "March" from "Expiration month"
|
73
78
|
And I select "2020" from "Expiration year"
|
79
|
+
And I fill in "Address Line 1" with "41 Winter St"
|
80
|
+
And I fill in "Address Line 2" with "Floor 7"
|
81
|
+
And I fill in "City" with "Boston"
|
82
|
+
And I fill in "State or Province" with "MA"
|
83
|
+
And I fill in "ZIP or Postal Code" with "02108"
|
84
|
+
And I select "United States of America" from "Country"
|
74
85
|
When I press "Upgrade"
|
75
86
|
Then I should not see "Plan changed successfully"
|
76
87
|
And "Card number" should have the error "is invalid"
|
@@ -78,7 +89,7 @@ Feature: Manage Plan
|
|
78
89
|
Scenario: Change the plan to a free on an account with a paid plan
|
79
90
|
Given a paid plan exists with a name of "Basic"
|
80
91
|
And a plan exists with a name of "Free"
|
81
|
-
And the following account exists:
|
92
|
+
And the following paid account exists:
|
82
93
|
| name | keyword | plan | cardholder_name | billing_email | card_number | verification_code | expiration_month | expiration_year |
|
83
94
|
| Test | test | name: Basic | Joe Smith | jsmith@example.com | 4111111111115555 | 122 | 01 | 2015 |
|
84
95
|
And I have signed in with "joe@example.com"
|
@@ -97,7 +108,7 @@ Feature: Manage Plan
|
|
97
108
|
Scenario: Attempting to downgrade when beyond the limits
|
98
109
|
Given a paid plan exists with a name of "Basic"
|
99
110
|
And a plan exists with a name of "Free"
|
100
|
-
And the following account exists:
|
111
|
+
And the following paid account exists:
|
101
112
|
| name | keyword | plan | cardholder_name | billing_email | card_number | verification_code | expiration_month | expiration_year |
|
102
113
|
| Test | test | name: Basic | Joe Smith | jsmith@example.com | 4111111111115555 | 122 | 01 | 2015 |
|
103
114
|
And the following limits exist:
|
@@ -127,7 +138,7 @@ Feature: Manage Plan
|
|
127
138
|
|
128
139
|
Scenario: Viewing current usage
|
129
140
|
Given a paid plan exists with a name of "Basic"
|
130
|
-
And the following account exists:
|
141
|
+
And the following paid account exists:
|
131
142
|
| name | keyword | plan | cardholder_name | billing_email | card_number | verification_code | expiration_month | expiration_year |
|
132
143
|
| Test | test | name: Basic | Joe Smith | jsmith@example.com | 4111111111115555 | 122 | 01 | 2015 |
|
133
144
|
And the following limits exist:
|
@@ -31,6 +31,12 @@ Feature: Sign up
|
|
31
31
|
And I fill in "Verification code" with "123"
|
32
32
|
And I select "March" from "Expiration month"
|
33
33
|
And I select "2020" from "Expiration year"
|
34
|
+
And I fill in "Address Line 1" with "123 Robo Lane"
|
35
|
+
And I fill in "Address Line 2" with "Suite 5"
|
36
|
+
And I fill in "City" with "Boston"
|
37
|
+
And I fill in "State or Province" with "MA"
|
38
|
+
And I fill in "ZIP or Postal Code" with "02110"
|
39
|
+
And I select "United States of America" from "Country"
|
34
40
|
And I press "Sign up"
|
35
41
|
Then I should see "created"
|
36
42
|
|
@@ -46,6 +52,12 @@ Feature: Sign up
|
|
46
52
|
And I fill in "Verification code" with "123"
|
47
53
|
And I select "March" from "Expiration month"
|
48
54
|
And I select "2020" from "Expiration year"
|
55
|
+
And I fill in "Address Line 1" with "123 Robo Lane"
|
56
|
+
And I fill in "Address Line 2" with "Suite 5"
|
57
|
+
And I fill in "City" with "Boston"
|
58
|
+
And I fill in "State or Province" with "MA"
|
59
|
+
And I fill in "ZIP or Postal Code" with "02110"
|
60
|
+
And I select "United States of America" from "Country"
|
49
61
|
And I press "Sign up"
|
50
62
|
Then "Card number" should have the error "is invalid"
|
51
63
|
|
@@ -61,5 +73,11 @@ Feature: Sign up
|
|
61
73
|
And I fill in "Verification code" with "123"
|
62
74
|
And I select "March" from "Expiration month"
|
63
75
|
And I select "2020" from "Expiration year"
|
76
|
+
And I fill in "Address Line 1" with "123 Robo Lane"
|
77
|
+
And I fill in "Address Line 2" with "Suite 5"
|
78
|
+
And I fill in "City" with "Boston"
|
79
|
+
And I fill in "State or Province" with "MA"
|
80
|
+
And I fill in "ZIP or Postal Code" with "02110"
|
81
|
+
And I select "United States of America" from "Country"
|
64
82
|
And I press "Sign up"
|
65
83
|
Then "Card number" should have the error "Do Not Honor"
|
@@ -37,15 +37,6 @@ Feature: Trial plans
|
|
37
37
|
And I should see "expired"
|
38
38
|
And the "Temp" plan should be disabled
|
39
39
|
|
40
|
-
Scenario: Delete an account with an expired plan
|
41
|
-
Given a "Temp" account exists with a name of "Test" created 30 days ago
|
42
|
-
And I am signed in as an admin of the "Test" account
|
43
|
-
When I go to the projects page for the "Test" account
|
44
|
-
Then I should be on the upgrade plan page for the "Test" account
|
45
|
-
And I should see "expired"
|
46
|
-
When I follow "No thanks, just delete my account"
|
47
|
-
Then I should see "Your account has been deleted"
|
48
|
-
|
49
40
|
Scenario: Sign up for a non-trial plan
|
50
41
|
When I go to the list of plans page
|
51
42
|
And I follow "Eternal"
|
@@ -0,0 +1,8 @@
|
|
1
|
+
Then /^I should see all the Braintree countries in the country select with the following at the top:$/ do |table|
|
2
|
+
divider = "---"
|
3
|
+
top_country_names = table.raw.flatten
|
4
|
+
all_country_names = Braintree::Address::CountryNames.map(&:first)
|
5
|
+
|
6
|
+
expected_country_names = [top_country_names, divider, all_country_names].flatten
|
7
|
+
page.should have_select("Country", :options => expected_country_names)
|
8
|
+
end
|
data/lib/saucy/subscription.rb
CHANGED
@@ -10,16 +10,28 @@ module Saucy
|
|
10
10
|
|
11
11
|
extend ActiveSupport::Memoizable
|
12
12
|
|
13
|
-
CUSTOMER_ATTRIBUTES =
|
14
|
-
:billing_email
|
15
|
-
:card_number
|
16
|
-
:expiration_month
|
17
|
-
:expiration_year
|
18
|
-
:verification_code
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
13
|
+
CUSTOMER_ATTRIBUTES = [ :cardholder_name,
|
14
|
+
:billing_email,
|
15
|
+
:card_number,
|
16
|
+
:expiration_month,
|
17
|
+
:expiration_year,
|
18
|
+
:verification_code,
|
19
|
+
:street_address,
|
20
|
+
:extended_address,
|
21
|
+
:locality,
|
22
|
+
:region,
|
23
|
+
:postal_code,
|
24
|
+
:country_name
|
25
|
+
]
|
26
|
+
|
27
|
+
OPTIONAL_CUSTOMER_ATTRIBUTES = [:extended_address]
|
28
|
+
|
29
|
+
REQUIRED_CUSTOMER_ATTRIBUTES =
|
30
|
+
CUSTOMER_ATTRIBUTES - OPTIONAL_CUSTOMER_ATTRIBUTES
|
31
|
+
|
32
|
+
attr_accessor *CUSTOMER_ATTRIBUTES
|
33
|
+
|
34
|
+
REQUIRED_CUSTOMER_ATTRIBUTES.each do |attribute|
|
23
35
|
validates_presence_of attribute, :if => :switching_to_billed?
|
24
36
|
end
|
25
37
|
before_create :create_customer
|
@@ -39,6 +51,10 @@ module Saucy
|
|
39
51
|
customer.credit_cards[0] if customer && customer.credit_cards.any?
|
40
52
|
end
|
41
53
|
|
54
|
+
def billing_address
|
55
|
+
credit_card.billing_address if credit_card
|
56
|
+
end
|
57
|
+
|
42
58
|
def subscription
|
43
59
|
Braintree::Subscription.find(subscription_token) if subscription_token
|
44
60
|
end
|
@@ -103,11 +119,11 @@ module Saucy
|
|
103
119
|
end
|
104
120
|
|
105
121
|
def changing_customer_attributes?(attributes)
|
106
|
-
CUSTOMER_ATTRIBUTES.
|
122
|
+
CUSTOMER_ATTRIBUTES.any? { |attribute| attributes[attribute].present? }
|
107
123
|
end
|
108
124
|
|
109
125
|
def set_customer_attributes(attributes)
|
110
|
-
CUSTOMER_ATTRIBUTES.
|
126
|
+
CUSTOMER_ATTRIBUTES.each do |attribute|
|
111
127
|
send("#{attribute}=", attributes[attribute]) if attributes[attribute].present?
|
112
128
|
end
|
113
129
|
end
|
@@ -144,7 +160,16 @@ module Saucy
|
|
144
160
|
:number => card_number,
|
145
161
|
:expiration_month => expiration_month,
|
146
162
|
:expiration_year => expiration_year,
|
147
|
-
:cvv => verification_code
|
163
|
+
:cvv => verification_code,
|
164
|
+
:billing_address => {
|
165
|
+
:street_address => street_address,
|
166
|
+
:extended_address => extended_address,
|
167
|
+
:locality => locality,
|
168
|
+
:region => region,
|
169
|
+
:postal_code => postal_code,
|
170
|
+
:country_name => country_name
|
171
|
+
}
|
172
|
+
}
|
148
173
|
if credit_card
|
149
174
|
card_attributes.merge!(:options => credit_card_options)
|
150
175
|
end
|
@@ -1,17 +1,22 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
+
describe Account, "factories" do
|
4
|
+
it "has a valid factory" do
|
5
|
+
Factory(:account).should be_valid
|
6
|
+
end
|
7
|
+
|
8
|
+
it "has a valid paid factory" do
|
9
|
+
Factory(:paid_account).should be_valid
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
3
13
|
describe Account do
|
4
14
|
subject { Factory(:account) }
|
5
15
|
|
6
16
|
it "manifests braintree processor_declined errors as errors on number and doesn't save" do
|
7
17
|
FakeBraintree.failures["4111111111111112"] = { "message" => "Do Not Honor", "code" => "2000", "status" => "processor_declined" }
|
8
|
-
account = Factory.build(:
|
9
|
-
:cardholder_name => "Ralph Robot",
|
10
|
-
:billing_email => "ralph@example.com",
|
18
|
+
account = Factory.build(:paid_account,
|
11
19
|
:card_number => "4111111111111112",
|
12
|
-
:verification_code => "100",
|
13
|
-
:expiration_month => 5,
|
14
|
-
:expiration_year => 2012,
|
15
20
|
:plan => Factory(:paid_plan))
|
16
21
|
account.save.should_not be
|
17
22
|
FakeBraintree.customers.should be_empty
|
@@ -21,13 +26,8 @@ describe Account do
|
|
21
26
|
|
22
27
|
it "manifests braintree gateway_rejected errors as errors on number and doesn't save" do
|
23
28
|
FakeBraintree.failures["4111111111111112"] = { "message" => "Gateway Rejected: cvv", "code" => "N", "status" => "gateway_rejected" }
|
24
|
-
account = Factory.build(:
|
25
|
-
:cardholder_name => "Ralph Robot",
|
26
|
-
:billing_email => "ralph@example.com",
|
29
|
+
account = Factory.build(:paid_account,
|
27
30
|
:card_number => "4111111111111112",
|
28
|
-
:expiration_month => 5,
|
29
|
-
:expiration_year => 2012,
|
30
|
-
:verification_code => 200,
|
31
31
|
:plan => Factory(:paid_plan))
|
32
32
|
account.save.should_not be
|
33
33
|
FakeBraintree.customers.should be_empty
|
@@ -36,14 +36,9 @@ describe Account do
|
|
36
36
|
end
|
37
37
|
|
38
38
|
it "manifests braintree gateway_rejected errors as errors on number and doesn't save" do
|
39
|
-
FakeBraintree.failures["
|
40
|
-
account = Factory.build(:
|
41
|
-
:
|
42
|
-
:billing_email => "ralph@example.com",
|
43
|
-
:card_number => "4111111111111111",
|
44
|
-
:expiration_month => 5,
|
45
|
-
:expiration_year => 2012,
|
46
|
-
:verification_code => 123,
|
39
|
+
FakeBraintree.failures["4111111111111112"] = { "message" => "Credit card number is invalid.", "errors" => { "customer" => { "errors" => [], "credit-card" => { "errors" => [{ "message" => "Credit card number is invalid.", "code" => 81715, "attribute" => :number }] }}}}
|
40
|
+
account = Factory.build(:paid_account,
|
41
|
+
:card_number => "4111111111111112",
|
47
42
|
:plan => Factory(:paid_plan))
|
48
43
|
account.save.should_not be
|
49
44
|
FakeBraintree.customers.should be_empty
|
@@ -64,7 +59,7 @@ describe Account, "given free and paid plans" do
|
|
64
59
|
|
65
60
|
result.should be_false
|
66
61
|
account.reload.plan.should == free
|
67
|
-
Saucy::Subscription::
|
62
|
+
Saucy::Subscription::REQUIRED_CUSTOMER_ATTRIBUTES.each do |attribute|
|
68
63
|
account.errors[attribute].should_not be_blank
|
69
64
|
end
|
70
65
|
FakeBraintree.customers[account.customer_token].should_not be_nil
|
@@ -92,14 +87,7 @@ end
|
|
92
87
|
|
93
88
|
describe Account, "with a paid plan" do
|
94
89
|
subject do
|
95
|
-
Factory(:
|
96
|
-
:cardholder_name => "Ralph Robot",
|
97
|
-
:billing_email => "ralph@example.com",
|
98
|
-
:card_number => "4111111111111111",
|
99
|
-
:verification_code => "123",
|
100
|
-
:expiration_month => 5,
|
101
|
-
:expiration_year => 2012,
|
102
|
-
:plan => Factory(:paid_plan))
|
90
|
+
Factory(:paid_account, :plan => Factory(:paid_plan))
|
103
91
|
end
|
104
92
|
|
105
93
|
it "has a customer_token" do
|
@@ -148,15 +136,76 @@ describe Account, "with a paid plan" do
|
|
148
136
|
FakeBraintree.subscriptions[subject.subscription_token]["price"].should == "5"
|
149
137
|
end
|
150
138
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
139
|
+
context "updating customer credit card information when changed" do
|
140
|
+
before do
|
141
|
+
subject.save_customer_and_subscription!(:billing_email => "jrobot@example.com",
|
142
|
+
:cardholder_name => "Jim Robot",
|
143
|
+
:card_number => "4111111111111115",
|
144
|
+
:verification_code => "123",
|
145
|
+
:expiration_month => 5,
|
146
|
+
:expiration_year => 2013)
|
147
|
+
end
|
148
|
+
|
149
|
+
it "updates the billing email" do
|
150
|
+
subject.customer.email.should == "jrobot@example.com"
|
151
|
+
end
|
152
|
+
|
153
|
+
it "updates the cardholder name" do
|
154
|
+
subject.credit_card.cardholder_name.should == "Jim Robot"
|
155
|
+
end
|
156
|
+
|
157
|
+
it "updates the card number" do
|
158
|
+
subject.credit_card.last_4.should == "1115"
|
159
|
+
end
|
160
|
+
|
161
|
+
it "updates the expiration year" do
|
162
|
+
subject.credit_card.expiration_year.should == 2013
|
163
|
+
end
|
164
|
+
|
165
|
+
it "updates the expiration month" do
|
166
|
+
subject.credit_card.expiration_month.should == 5
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
context "updating customer credit card billing address information when changed" do
|
171
|
+
before do
|
172
|
+
subject.save_customer_and_subscription!(:billing_email => "jrobot@example.com",
|
173
|
+
:cardholder_name => "Jim Robot",
|
174
|
+
:card_number => "4111111111111115",
|
175
|
+
:verification_code => "123",
|
176
|
+
:expiration_month => 5,
|
177
|
+
:expiration_year => 2013,
|
178
|
+
:street_address => "1 E Main St",
|
179
|
+
:extended_address => "Suite 3",
|
180
|
+
:locality => "Chicago",
|
181
|
+
:region => "Illinois",
|
182
|
+
:postal_code => "60622",
|
183
|
+
:country_name => "United States of America")
|
184
|
+
end
|
185
|
+
|
186
|
+
it "updates the street address" do
|
187
|
+
subject.billing_address.street_address.should == "1 E Main St"
|
188
|
+
end
|
189
|
+
|
190
|
+
it "updates the extended address" do
|
191
|
+
subject.billing_address.extended_address.should == "Suite 3"
|
192
|
+
end
|
193
|
+
|
194
|
+
it "updates the locality" do
|
195
|
+
subject.billing_address.locality.should == "Chicago"
|
196
|
+
end
|
197
|
+
|
198
|
+
it "updates the region" do
|
199
|
+
subject.billing_address.region.should == "Illinois"
|
200
|
+
end
|
201
|
+
|
202
|
+
it "updates the postal code" do
|
203
|
+
subject.billing_address.postal_code.should == "60622"
|
204
|
+
end
|
205
|
+
|
206
|
+
it "updates the country name" do
|
207
|
+
subject.billing_address.country_name.should == "United States of America"
|
208
|
+
end
|
160
209
|
end
|
161
210
|
|
162
211
|
it "deletes the customer when deleted" do
|
@@ -190,6 +239,10 @@ describe Account, "with a free plan" do
|
|
190
239
|
subject.subscription.should be_nil
|
191
240
|
end
|
192
241
|
|
242
|
+
it "doesn't have a billing address" do
|
243
|
+
subject.billing_address.should be_nil
|
244
|
+
end
|
245
|
+
|
193
246
|
it "creates a braintree customer" do
|
194
247
|
FakeBraintree.customers[subject.customer_token].should_not be_nil
|
195
248
|
end
|
@@ -199,34 +252,23 @@ describe Account, "with a free plan" do
|
|
199
252
|
FakeBraintree.subscriptions[subject.subscription_token].should be_nil
|
200
253
|
end
|
201
254
|
|
202
|
-
it "creates a credit card, and
|
255
|
+
it "creates a credit card, subscription, and billing address when the plan is changed to a paid plan and the billing info is supplied" do
|
203
256
|
new_plan = Factory(:paid_plan, :name => "New Plan")
|
204
|
-
subject.save_customer_and_subscription!(:plan_id => new_plan.id
|
205
|
-
:cardholder_name => "Ralph Robot",
|
206
|
-
:billing_email => "ralph@example.com",
|
207
|
-
:card_number => "4111111111111111",
|
208
|
-
:verification_code => "123",
|
209
|
-
:expiration_month => 5,
|
210
|
-
:expiration_year => 2012)
|
257
|
+
subject.save_customer_and_subscription!(Factory.attributes_for(:paid_account, :plan_id => new_plan.id))
|
211
258
|
|
212
259
|
FakeBraintree.customers[subject.customer_token]["credit_cards"].first.should_not be_nil
|
213
260
|
FakeBraintree.subscriptions[subject.subscription_token].should_not be_nil
|
214
261
|
FakeBraintree.subscriptions[subject.subscription_token]["plan_id"].should == new_plan.id
|
215
262
|
subject.credit_card.should_not be_nil
|
216
263
|
subject.subscription.should_not be_nil
|
264
|
+
subject.billing_address.should_not be_nil
|
217
265
|
end
|
218
266
|
|
219
267
|
it "passes up the merchant_account_id on the subscription when it's configured" do
|
220
268
|
begin
|
221
269
|
Saucy::Configuration.merchant_account_id = 'test'
|
222
270
|
new_plan = Factory(:paid_plan, :name => "New Plan")
|
223
|
-
subject.save_customer_and_subscription!(:plan_id => new_plan.id
|
224
|
-
:cardholder_name => "Ralph Robot",
|
225
|
-
:billing_email => "ralph@example.com",
|
226
|
-
:card_number => "4111111111111111",
|
227
|
-
:verification_code => "123",
|
228
|
-
:expiration_month => 5,
|
229
|
-
:expiration_year => 2012)
|
271
|
+
subject.save_customer_and_subscription!(Factory.attributes_for(:paid_account, :plan_id => new_plan.id))
|
230
272
|
|
231
273
|
FakeBraintree.subscriptions[subject.subscription_token]["merchant_account_id"].should == 'test'
|
232
274
|
ensure
|
@@ -237,23 +279,18 @@ describe Account, "with a free plan" do
|
|
237
279
|
it "doesn't pass up the merchant_account_id on the subscription when it's not configured" do
|
238
280
|
Saucy::Configuration.merchant_account_id = nil
|
239
281
|
new_plan = Factory(:paid_plan, :name => "New Plan")
|
240
|
-
subject.save_customer_and_subscription!(:plan_id => new_plan.id
|
241
|
-
:cardholder_name => "Ralph Robot",
|
242
|
-
:billing_email => "ralph@example.com",
|
243
|
-
:card_number => "4111111111111111",
|
244
|
-
:verification_code => "123",
|
245
|
-
:expiration_month => 5,
|
246
|
-
:expiration_year => 2012)
|
282
|
+
subject.save_customer_and_subscription!(Factory.attributes_for(:paid_account, :plan_id => new_plan.id))
|
247
283
|
|
248
284
|
FakeBraintree.subscriptions[subject.subscription_token].keys.should_not include("merchant_account_id")
|
249
285
|
end
|
250
286
|
|
251
|
-
it "doesn't create a credit card, and
|
287
|
+
it "doesn't create a credit card, subscription, and billing address when the plan is changed to a different free plan" do
|
252
288
|
new_plan = Factory(:plan, :name => "New Plan")
|
253
289
|
subject.save_customer_and_subscription!(:plan_id => new_plan.id)
|
254
290
|
|
255
291
|
subject.credit_card.should be_nil
|
256
292
|
subject.subscription.should be_nil
|
293
|
+
subject.billing_address.should be_nil
|
257
294
|
end
|
258
295
|
end
|
259
296
|
|
@@ -285,16 +322,12 @@ end
|
|
285
322
|
|
286
323
|
describe Account, "with a paid subscription" do
|
287
324
|
subject do
|
288
|
-
Factory(:
|
289
|
-
:cardholder_name => "Ralph Robot",
|
290
|
-
:billing_email => "ralph@example.com",
|
291
|
-
:card_number => "4111111111111111",
|
292
|
-
:verification_code => "123",
|
293
|
-
:expiration_month => 5,
|
294
|
-
:expiration_year => 2012,
|
325
|
+
Factory(:paid_account,
|
295
326
|
:plan => Factory(:paid_plan))
|
296
327
|
end
|
297
328
|
|
329
|
+
let(:merchant_time_zone) { ActiveSupport::TimeZone[Saucy::Configuration.merchant_account_time_zone] }
|
330
|
+
|
298
331
|
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
|
299
332
|
next_billing_date_string = 2.months.from_now.to_s(:braintree_date)
|
300
333
|
subscription = FakeBraintree.subscriptions[subject.subscription_token]
|
@@ -304,8 +337,7 @@ describe Account, "with a paid subscription" do
|
|
304
337
|
Timecop.travel(subject.next_billing_date + 1.day) do
|
305
338
|
Account.update_subscriptions!
|
306
339
|
subject.reload.subscription_status.should == Braintree::Subscription::Status::PastDue
|
307
|
-
subject.next_billing_date.should ==
|
308
|
-
Saucy::Configuration.merchant_account_time_zone)
|
340
|
+
subject.next_billing_date.should == merchant_time_zone.parse(next_billing_date_string)
|
309
341
|
subject.past_due?.should be
|
310
342
|
end
|
311
343
|
end
|
@@ -326,13 +358,7 @@ describe Account, "with a paid subscription" do
|
|
326
358
|
end
|
327
359
|
|
328
360
|
it "delivers the rest of the emails even if one fails" do
|
329
|
-
Factory(:
|
330
|
-
:cardholder_name => "Ralph Robot",
|
331
|
-
:billing_email => "ralph@example.com",
|
332
|
-
:card_number => "4111111111111111",
|
333
|
-
:verification_code => "123",
|
334
|
-
:expiration_month => 5,
|
335
|
-
:expiration_year => 2012,
|
361
|
+
Factory(:paid_account,
|
336
362
|
:plan => Factory(:paid_plan))
|
337
363
|
Timecop.travel(subject.next_billing_date + 1.day) do
|
338
364
|
Account.update_subscriptions!
|
@@ -519,13 +545,7 @@ end
|
|
519
545
|
|
520
546
|
describe Account, "with a paid subscription that is past due" do
|
521
547
|
subject do
|
522
|
-
Factory(:
|
523
|
-
:cardholder_name => "Ralph Robot",
|
524
|
-
:billing_email => "ralph@example.com",
|
525
|
-
:card_number => "4111111111111111",
|
526
|
-
:verification_code => "123",
|
527
|
-
:expiration_month => 5,
|
528
|
-
:expiration_year => 2012,
|
548
|
+
Factory(:paid_account,
|
529
549
|
:plan => Factory(:paid_plan))
|
530
550
|
end
|
531
551
|
|
@@ -622,13 +642,7 @@ end
|
|
622
642
|
|
623
643
|
describe Account, "that is activated" do
|
624
644
|
subject do
|
625
|
-
Factory(:
|
626
|
-
:cardholder_name => "Ralph Robot",
|
627
|
-
:billing_email => "ralph@example.com",
|
628
|
-
:card_number => "4111111111111111",
|
629
|
-
:verification_code => "123",
|
630
|
-
:expiration_month => 5,
|
631
|
-
:expiration_year => 2012,
|
645
|
+
Factory(:paid_account,
|
632
646
|
:plan => Factory(:paid_plan))
|
633
647
|
end
|
634
648
|
|
metadata
CHANGED
@@ -1,13 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: saucy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash: 45
|
5
4
|
prerelease:
|
6
|
-
|
7
|
-
- 0
|
8
|
-
- 13
|
9
|
-
- 3
|
10
|
-
version: 0.13.3
|
5
|
+
version: 0.14.0
|
11
6
|
platform: ruby
|
12
7
|
authors:
|
13
8
|
- thoughtbot, inc.
|
@@ -20,7 +15,7 @@ autorequire:
|
|
20
15
|
bindir: bin
|
21
16
|
cert_chain: []
|
22
17
|
|
23
|
-
date: 2011-10-
|
18
|
+
date: 2011-10-24 00:00:00 Z
|
24
19
|
dependencies:
|
25
20
|
- !ruby/object:Gem::Dependency
|
26
21
|
name: clearance
|
@@ -30,11 +25,6 @@ dependencies:
|
|
30
25
|
requirements:
|
31
26
|
- - ~>
|
32
27
|
- !ruby/object:Gem::Version
|
33
|
-
hash: 55
|
34
|
-
segments:
|
35
|
-
- 0
|
36
|
-
- 11
|
37
|
-
- 2
|
38
28
|
version: 0.11.2
|
39
29
|
type: :runtime
|
40
30
|
version_requirements: *id001
|
@@ -46,10 +36,6 @@ dependencies:
|
|
46
36
|
requirements:
|
47
37
|
- - ">="
|
48
38
|
- !ruby/object:Gem::Version
|
49
|
-
hash: 11
|
50
|
-
segments:
|
51
|
-
- 1
|
52
|
-
- 2
|
53
39
|
version: "1.2"
|
54
40
|
type: :runtime
|
55
41
|
version_requirements: *id002
|
@@ -61,11 +47,6 @@ dependencies:
|
|
61
47
|
requirements:
|
62
48
|
- - ">="
|
63
49
|
- !ruby/object:Gem::Version
|
64
|
-
hash: 1
|
65
|
-
segments:
|
66
|
-
- 3
|
67
|
-
- 0
|
68
|
-
- 3
|
69
50
|
version: 3.0.3
|
70
51
|
type: :runtime
|
71
52
|
version_requirements: *id003
|
@@ -77,11 +58,6 @@ dependencies:
|
|
77
58
|
requirements:
|
78
59
|
- - ">="
|
79
60
|
- !ruby/object:Gem::Version
|
80
|
-
hash: 19
|
81
|
-
segments:
|
82
|
-
- 2
|
83
|
-
- 6
|
84
|
-
- 2
|
85
61
|
version: 2.6.2
|
86
62
|
type: :runtime
|
87
63
|
version_requirements: *id004
|
@@ -93,11 +69,6 @@ dependencies:
|
|
93
69
|
requirements:
|
94
70
|
- - "="
|
95
71
|
- !ruby/object:Gem::Version
|
96
|
-
hash: 29
|
97
|
-
segments:
|
98
|
-
- 1
|
99
|
-
- 3
|
100
|
-
- 3
|
101
72
|
version: 1.3.3
|
102
73
|
type: :runtime
|
103
74
|
version_requirements: *id005
|
@@ -109,11 +80,6 @@ dependencies:
|
|
109
80
|
requirements:
|
110
81
|
- - ">="
|
111
82
|
- !ruby/object:Gem::Version
|
112
|
-
hash: 23
|
113
|
-
segments:
|
114
|
-
- 1
|
115
|
-
- 1
|
116
|
-
- 2
|
117
83
|
version: 1.1.2
|
118
84
|
type: :runtime
|
119
85
|
version_requirements: *id006
|
@@ -125,11 +91,6 @@ dependencies:
|
|
125
91
|
requirements:
|
126
92
|
- - ~>
|
127
93
|
- !ruby/object:Gem::Version
|
128
|
-
hash: 15
|
129
|
-
segments:
|
130
|
-
- 3
|
131
|
-
- 0
|
132
|
-
- 4
|
133
94
|
version: 3.0.4
|
134
95
|
type: :runtime
|
135
96
|
version_requirements: *id007
|
@@ -141,11 +102,6 @@ dependencies:
|
|
141
102
|
requirements:
|
142
103
|
- - "="
|
143
104
|
- !ruby/object:Gem::Version
|
144
|
-
hash: 27
|
145
|
-
segments:
|
146
|
-
- 0
|
147
|
-
- 2
|
148
|
-
- 6
|
149
105
|
version: 0.2.6
|
150
106
|
type: :development
|
151
107
|
version_requirements: *id008
|
@@ -238,6 +194,7 @@ files:
|
|
238
194
|
- lib/generators/saucy/features/templates/factories.rb
|
239
195
|
- lib/generators/saucy/features/templates/step_definitions/account_steps.rb
|
240
196
|
- lib/generators/saucy/features/templates/step_definitions/braintree_steps.rb
|
197
|
+
- lib/generators/saucy/features/templates/step_definitions/country_steps.rb
|
241
198
|
- lib/generators/saucy/features/templates/step_definitions/cron_steps.rb
|
242
199
|
- lib/generators/saucy/features/templates/step_definitions/email_steps.rb
|
243
200
|
- lib/generators/saucy/features/templates/step_definitions/factory_girl_steps.rb
|
@@ -345,23 +302,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
345
302
|
requirements:
|
346
303
|
- - ">="
|
347
304
|
- !ruby/object:Gem::Version
|
348
|
-
hash: 3
|
349
|
-
segments:
|
350
|
-
- 0
|
351
305
|
version: "0"
|
352
306
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
353
307
|
none: false
|
354
308
|
requirements:
|
355
309
|
- - ">="
|
356
310
|
- !ruby/object:Gem::Version
|
357
|
-
hash: 3
|
358
|
-
segments:
|
359
|
-
- 0
|
360
311
|
version: "0"
|
361
312
|
requirements: []
|
362
313
|
|
363
314
|
rubyforge_project:
|
364
|
-
rubygems_version: 1.8.
|
315
|
+
rubygems_version: 1.8.10
|
365
316
|
signing_key:
|
366
317
|
specification_version: 3
|
367
318
|
summary: Clearance-based Rails engine for SaaS
|