ashmont 0.0.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/CHANGELOG.md +8 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +21 -0
- data/README.md +119 -0
- data/Rakefile +8 -0
- data/ashmont.gemspec +29 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/ashmont/customer.rb +146 -0
- data/lib/ashmont/errors.rb +47 -0
- data/lib/ashmont/subscribed_customer.rb +80 -0
- data/lib/ashmont/subscription.rb +104 -0
- data/lib/ashmont/version.rb +3 -0
- data/lib/ashmont.rb +13 -0
- data/spec/ashmont/customer_spec.rb +286 -0
- data/spec/ashmont/errors_spec.rb +51 -0
- data/spec/ashmont/subscribed_customer_spec.rb +123 -0
- data/spec/ashmont/subscription_spec.rb +204 -0
- data/spec/ashmont_spec.rb +11 -0
- data/spec/spec_helper.rb +8 -0
- metadata +187 -0
@@ -0,0 +1,104 @@
|
|
1
|
+
require "ashmont/errors"
|
2
|
+
require "active_support/core_ext"
|
3
|
+
require "braintree"
|
4
|
+
|
5
|
+
module Ashmont
|
6
|
+
class Subscription
|
7
|
+
attr_reader :token, :errors
|
8
|
+
|
9
|
+
def initialize(token = nil, cached_attributes = {})
|
10
|
+
@token = token
|
11
|
+
@cached_attributes = cached_attributes
|
12
|
+
@errors = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
delegate :transactions, :to => :remote_subscription, :allow_nil => true
|
16
|
+
|
17
|
+
def status
|
18
|
+
@cached_attributes[:status] || remote_status
|
19
|
+
end
|
20
|
+
|
21
|
+
def save(attributes)
|
22
|
+
attributes_for_merchant = add_merchant_to_attributes(attributes)
|
23
|
+
if token
|
24
|
+
update(attributes_for_merchant)
|
25
|
+
else
|
26
|
+
create(attributes_for_merchant)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def retry_charge
|
31
|
+
transaction = Braintree::Subscription.retry_charge(token).transaction
|
32
|
+
result = Braintree::Transaction.submit_for_settlement(transaction.id)
|
33
|
+
reload
|
34
|
+
if result.success?
|
35
|
+
true
|
36
|
+
else
|
37
|
+
@errors = Ashmont::Errors.new(transaction, result.errors)
|
38
|
+
false
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def most_recent_transaction
|
43
|
+
transactions.sort_by(&:created_at).last
|
44
|
+
end
|
45
|
+
|
46
|
+
def next_billing_date
|
47
|
+
merchant_account_time_zone.parse(remote_subscription.next_billing_date) if remote_subscription
|
48
|
+
end
|
49
|
+
|
50
|
+
def reload
|
51
|
+
@remote_subscription = nil
|
52
|
+
@cached_attributes = {}
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
def past_due?
|
57
|
+
status == Braintree::Subscription::Status::PastDue
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def remote_status
|
63
|
+
remote_subscription.status if remote_subscription
|
64
|
+
end
|
65
|
+
|
66
|
+
def add_merchant_to_attributes(attributes)
|
67
|
+
if Ashmont.merchant_account_id
|
68
|
+
attributes.merge(:merchant_account_id => Ashmont.merchant_account_id)
|
69
|
+
else
|
70
|
+
attributes
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def create(attributes)
|
75
|
+
result = Braintree::Subscription.create(attributes)
|
76
|
+
if result.success?
|
77
|
+
@token = result.subscription.id
|
78
|
+
@remote_subscription = result.subscription
|
79
|
+
true
|
80
|
+
else
|
81
|
+
false
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def update(attributes)
|
86
|
+
@remote_subscription = nil
|
87
|
+
Braintree::Subscription.update(token, attributes)
|
88
|
+
end
|
89
|
+
|
90
|
+
def remote_subscription
|
91
|
+
@remote_subscription ||= find_remote_subscription
|
92
|
+
end
|
93
|
+
|
94
|
+
def find_remote_subscription
|
95
|
+
if token
|
96
|
+
Braintree::Subscription.find(token)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def merchant_account_time_zone
|
101
|
+
ActiveSupport::TimeZone[Ashmont.merchant_account_time_zone]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
data/lib/ashmont.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require "ashmont/version"
|
2
|
+
require "ashmont/subscription"
|
3
|
+
require "ashmont/customer"
|
4
|
+
require "ashmont/subscribed_customer"
|
5
|
+
|
6
|
+
module Ashmont
|
7
|
+
class << self
|
8
|
+
attr_accessor :merchant_account_time_zone
|
9
|
+
attr_accessor :merchant_account_id
|
10
|
+
end
|
11
|
+
|
12
|
+
self.merchant_account_time_zone = 'Eastern Time (US & Canada)'
|
13
|
+
end
|
@@ -0,0 +1,286 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ashmont/customer'
|
3
|
+
|
4
|
+
describe Ashmont::Customer do
|
5
|
+
it "returns its first credit card" do
|
6
|
+
token = "xyz"
|
7
|
+
remote_customer = stub("customer", :credit_cards => ["first", "second"])
|
8
|
+
Braintree::Customer.stubs(:find => remote_customer)
|
9
|
+
|
10
|
+
result = Ashmont::Customer.new(token).credit_card
|
11
|
+
|
12
|
+
Braintree::Customer.should have_received(:find).with(token)
|
13
|
+
result.should == "first"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "returns nothing without a remote customer" do
|
17
|
+
Ashmont::Customer.new.credit_card.should be_nil
|
18
|
+
end
|
19
|
+
|
20
|
+
it "returns all credit cards" do
|
21
|
+
token = "xyz"
|
22
|
+
remote_customer = stub("customer", :credit_cards => ["first", "second"])
|
23
|
+
Braintree::Customer.stubs(:find => remote_customer)
|
24
|
+
|
25
|
+
result = Ashmont::Customer.new(token).credit_cards
|
26
|
+
|
27
|
+
Braintree::Customer.should have_received(:find).with(token)
|
28
|
+
result.should == ["first", "second"]
|
29
|
+
end
|
30
|
+
|
31
|
+
it "returns an empty array without a remote customer" do
|
32
|
+
Ashmont::Customer.new.credit_cards.should == []
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
it "returns the remote email" do
|
37
|
+
remote_customer = stub("customer", :email => "admin@example.com")
|
38
|
+
Braintree::Customer.stubs(:find => remote_customer)
|
39
|
+
|
40
|
+
Ashmont::Customer.new("abc").billing_email.should == "admin@example.com"
|
41
|
+
end
|
42
|
+
|
43
|
+
it "doesn't have an email without a remote customer" do
|
44
|
+
Ashmont::Customer.new.billing_email.should be_nil
|
45
|
+
end
|
46
|
+
|
47
|
+
it "creates a valid remote customer" do
|
48
|
+
token = "xyz"
|
49
|
+
remote_customer = stub("customer", :credit_cards => [], :id => token)
|
50
|
+
create_result = stub("result", :success? => true, :customer => remote_customer)
|
51
|
+
attributes = { "email" => "ben@example.com" }
|
52
|
+
Braintree::Customer.stubs(:create => create_result)
|
53
|
+
|
54
|
+
customer = Ashmont::Customer.new
|
55
|
+
customer.save(attributes).should be_true
|
56
|
+
|
57
|
+
Braintree::Customer.should have_received(:create).with(:email => "ben@example.com", :credit_card => {})
|
58
|
+
customer.token.should == token
|
59
|
+
customer.errors.should be_empty
|
60
|
+
end
|
61
|
+
|
62
|
+
it "creates a remote customer with a credit card" do
|
63
|
+
token = "xyz"
|
64
|
+
remote_customer = stub("customer", :credit_cards => [], :id => token)
|
65
|
+
create_result = stub("result", :success? => true, :customer => remote_customer)
|
66
|
+
attributes = { "email" => "ben@example.com" }
|
67
|
+
Braintree::Customer.stubs(:create => create_result)
|
68
|
+
|
69
|
+
customer = Ashmont::Customer.new
|
70
|
+
customer.save(
|
71
|
+
:email => "jrobot@example.com",
|
72
|
+
:cardholder_name => "Jim Robot",
|
73
|
+
:number => "4111111111111115",
|
74
|
+
:cvv => "123",
|
75
|
+
:expiration_month => 5,
|
76
|
+
:expiration_year => 2013,
|
77
|
+
:street_address => "1 E Main St",
|
78
|
+
:extended_address => "Suite 3",
|
79
|
+
:locality => "Chicago",
|
80
|
+
:region => "Illinois",
|
81
|
+
:postal_code => "60622",
|
82
|
+
:country_name => "United States of America"
|
83
|
+
)
|
84
|
+
|
85
|
+
Braintree::Customer.should have_received(:create).with(
|
86
|
+
:email => "jrobot@example.com",
|
87
|
+
:credit_card => {
|
88
|
+
:cardholder_name => "Jim Robot",
|
89
|
+
:number => "4111111111111115",
|
90
|
+
:cvv => "123",
|
91
|
+
:expiration_month => 5,
|
92
|
+
:expiration_year => 2013,
|
93
|
+
:billing_address => {
|
94
|
+
:street_address => "1 E Main St",
|
95
|
+
:extended_address => "Suite 3",
|
96
|
+
:locality => "Chicago",
|
97
|
+
:region => "Illinois",
|
98
|
+
:postal_code => "60622",
|
99
|
+
:country_name => "United States of America"
|
100
|
+
}
|
101
|
+
}
|
102
|
+
)
|
103
|
+
end
|
104
|
+
|
105
|
+
it "returns errors while creating an invalid remote customer" do
|
106
|
+
error_messages = "error messages"
|
107
|
+
errors = "errors"
|
108
|
+
verification = "failure"
|
109
|
+
create_result = stub("result",
|
110
|
+
:success? => false,
|
111
|
+
:errors => error_messages,
|
112
|
+
:credit_card_verification => verification)
|
113
|
+
Braintree::Customer.stubs(:create => create_result)
|
114
|
+
Ashmont::Errors.stubs(:new => errors)
|
115
|
+
|
116
|
+
customer = Ashmont::Customer.new
|
117
|
+
customer.save("email" => "ben.franklin@example.com").should be_false
|
118
|
+
|
119
|
+
Ashmont::Errors.should have_received(:new).with(verification, error_messages)
|
120
|
+
customer.errors.should == errors
|
121
|
+
end
|
122
|
+
|
123
|
+
it "updates a remote customer with valid changes" do
|
124
|
+
token = "xyz"
|
125
|
+
updates = { "email" => 'somebody@example.com' }
|
126
|
+
customer = stub("customer", :id => token, :email => "somebody@example.com")
|
127
|
+
update_result = stub('result', :success? => true, :customer => customer)
|
128
|
+
Braintree::Customer.stubs(:update => update_result)
|
129
|
+
|
130
|
+
customer = Ashmont::Customer.new(token)
|
131
|
+
customer.save(updates).should be_true
|
132
|
+
|
133
|
+
Braintree::Customer.should have_received(:update).with(token, :email => "somebody@example.com", :credit_card => {})
|
134
|
+
customer.billing_email.should == "somebody@example.com"
|
135
|
+
end
|
136
|
+
|
137
|
+
it "updates a remote customer with a credit card" do
|
138
|
+
token = "xyz"
|
139
|
+
payment_method_token = "abc"
|
140
|
+
credit_card = stub("credit_card", :token => payment_method_token)
|
141
|
+
remote_customer = stub("customer", :credit_cards => [credit_card], :id => token)
|
142
|
+
update_result = stub("result", :success? => true, :customer => remote_customer)
|
143
|
+
Braintree::Customer.stubs(:update => update_result)
|
144
|
+
Braintree::Customer.stubs(:find => remote_customer)
|
145
|
+
|
146
|
+
customer = Ashmont::Customer.new(token)
|
147
|
+
customer.save(
|
148
|
+
:email => "jrobot@example.com",
|
149
|
+
:cardholder_name => "Jim Robot",
|
150
|
+
:number => "4111111111111115",
|
151
|
+
:cvv => "123",
|
152
|
+
:expiration_month => 5,
|
153
|
+
:expiration_year => 2013,
|
154
|
+
:street_address => "1 E Main St",
|
155
|
+
:extended_address => "Suite 3",
|
156
|
+
:locality => "Chicago",
|
157
|
+
:region => "Illinois",
|
158
|
+
:postal_code => "60622",
|
159
|
+
:country_name => "United States of America"
|
160
|
+
)
|
161
|
+
|
162
|
+
Braintree::Customer.should have_received(:update).with(
|
163
|
+
token,
|
164
|
+
:email => "jrobot@example.com",
|
165
|
+
:credit_card => {
|
166
|
+
:cardholder_name => "Jim Robot",
|
167
|
+
:number => "4111111111111115",
|
168
|
+
:cvv => "123",
|
169
|
+
:expiration_month => 5,
|
170
|
+
:expiration_year => 2013,
|
171
|
+
:billing_address => {
|
172
|
+
:street_address => "1 E Main St",
|
173
|
+
:extended_address => "Suite 3",
|
174
|
+
:locality => "Chicago",
|
175
|
+
:region => "Illinois",
|
176
|
+
:postal_code => "60622",
|
177
|
+
:country_name => "United States of America"
|
178
|
+
},
|
179
|
+
:options => {
|
180
|
+
:update_existing_token => payment_method_token
|
181
|
+
}
|
182
|
+
}
|
183
|
+
)
|
184
|
+
end
|
185
|
+
|
186
|
+
it "returns errors while updating an invalid customer" do
|
187
|
+
error_messages = "error messages"
|
188
|
+
errors = "errors"
|
189
|
+
verification = "failure"
|
190
|
+
update_result = stub("result",
|
191
|
+
:success? => false,
|
192
|
+
:errors => error_messages,
|
193
|
+
:credit_card_verification => verification)
|
194
|
+
Braintree::Customer.stubs(:update => update_result)
|
195
|
+
Ashmont::Errors.stubs(:new => errors)
|
196
|
+
|
197
|
+
customer = Ashmont::Customer.new("xyz")
|
198
|
+
customer.save("email" => "ben.franklin@example.com").should be_false
|
199
|
+
|
200
|
+
Ashmont::Errors.should have_received(:new).with(verification, error_messages)
|
201
|
+
customer.errors.should == errors
|
202
|
+
end
|
203
|
+
|
204
|
+
it "delete a remote customer" do
|
205
|
+
token = "xyz"
|
206
|
+
Braintree::Customer.stubs(:delete)
|
207
|
+
|
208
|
+
customer = Ashmont::Customer.new(token)
|
209
|
+
customer.delete
|
210
|
+
|
211
|
+
Braintree::Customer.should have_received(:delete).with(token)
|
212
|
+
end
|
213
|
+
|
214
|
+
it "has billing info with a credit card" do
|
215
|
+
token = "abc"
|
216
|
+
credit_card = stub("credit_card", :token => token)
|
217
|
+
remote_customer = stub("customer", :credit_cards => [credit_card])
|
218
|
+
Braintree::Customer.stubs(:find => remote_customer)
|
219
|
+
|
220
|
+
customer = Ashmont::Customer.new("xyz")
|
221
|
+
customer.should have_billing_info
|
222
|
+
customer.payment_method_token.should == token
|
223
|
+
end
|
224
|
+
|
225
|
+
it "doesn't have billing info without a credit card" do
|
226
|
+
remote_customer = stub("customer", :credit_cards => [])
|
227
|
+
Braintree::Customer.stubs(:find => remote_customer)
|
228
|
+
|
229
|
+
customer = Ashmont::Customer.new("xyz")
|
230
|
+
customer.should_not have_billing_info
|
231
|
+
customer.payment_method_token.should be_nil
|
232
|
+
end
|
233
|
+
|
234
|
+
%w(last_4 cardholder_name expiration_month expiration_year).each do |credit_card_attribute|
|
235
|
+
it "delegates ##{credit_card_attribute} to its credit card" do
|
236
|
+
credit_card = stub("credit_card", credit_card_attribute => "expected")
|
237
|
+
remote_customer = stub("customer", :credit_cards => [credit_card])
|
238
|
+
Braintree::Customer.stubs(:find => remote_customer)
|
239
|
+
|
240
|
+
Ashmont::Customer.new("xyz").send(credit_card_attribute).should == "expected"
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
%w(street_address extended_address locality region postal_code country_name).each do |billing_address_attribute|
|
245
|
+
it "delegates ##{billing_address_attribute} to its billing address" do
|
246
|
+
billing_address = stub("billing_address", billing_address_attribute => "expected")
|
247
|
+
credit_card = stub("credit_card", :billing_address => billing_address)
|
248
|
+
remote_customer = stub("customer", :credit_cards => [credit_card])
|
249
|
+
Braintree::Customer.stubs(:find => remote_customer)
|
250
|
+
|
251
|
+
Ashmont::Customer.new("xyz").send(billing_address_attribute).should == "expected"
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
it "confirms a transparent redirect query string" do
|
256
|
+
token = "xyz"
|
257
|
+
query_string = "abcmagic"
|
258
|
+
remote_customer = stub("customer", :credit_cards => [], :id => token)
|
259
|
+
confirm_result = stub("result", :success? => true, :customer => remote_customer)
|
260
|
+
Braintree::TransparentRedirect.stubs(:confirm => confirm_result)
|
261
|
+
|
262
|
+
customer = Ashmont::Customer.new
|
263
|
+
customer.confirm(query_string).should be_true
|
264
|
+
|
265
|
+
Braintree::TransparentRedirect.should have_received(:confirm).with(query_string)
|
266
|
+
customer.token.should == token
|
267
|
+
end
|
268
|
+
|
269
|
+
it "adds errors for an invalid transparent redirect query string" do
|
270
|
+
error_messages = "error messages"
|
271
|
+
errors = "errors"
|
272
|
+
verification = "failure"
|
273
|
+
confirm_result = stub("result",
|
274
|
+
:success? => false,
|
275
|
+
:errors => error_messages,
|
276
|
+
:credit_card_verification => verification)
|
277
|
+
Braintree::TransparentRedirect.stubs(:confirm => confirm_result)
|
278
|
+
Ashmont::Errors.stubs(:new => errors)
|
279
|
+
|
280
|
+
customer = Ashmont::Customer.new
|
281
|
+
customer.confirm("abc").should be_false
|
282
|
+
|
283
|
+
Ashmont::Errors.should have_received(:new).with(verification, error_messages)
|
284
|
+
customer.errors.should == errors
|
285
|
+
end
|
286
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Ashmont::Errors do
|
4
|
+
it "adds an error for a declined number" do
|
5
|
+
errors_for(:status => "processor_declined", :processor_response_text => "failure").
|
6
|
+
should include("number was denied by the payment processor with the message: failure")
|
7
|
+
end
|
8
|
+
|
9
|
+
it "adds an error for a mismatched cvv" do
|
10
|
+
errors_for(:status => "gateway_rejected").should include("cvv did not match")
|
11
|
+
end
|
12
|
+
|
13
|
+
it "adds a generic card number error" do
|
14
|
+
errors_for(:messages => { :number => "Credit card number is unsupported" }).
|
15
|
+
should include("number is unsupported")
|
16
|
+
end
|
17
|
+
|
18
|
+
it "adds a generic cvv error" do
|
19
|
+
errors_for(:messages => { :CVV => "CVV is unsupported" }).
|
20
|
+
should include("cvv is unsupported")
|
21
|
+
end
|
22
|
+
|
23
|
+
it "adds a generic expiration_month error" do
|
24
|
+
errors_for(:messages => { :expiration_month => "Expiration month is unsupported" }).
|
25
|
+
should include("expiration_month is unsupported")
|
26
|
+
end
|
27
|
+
|
28
|
+
it "adds a generic expiration_year error" do
|
29
|
+
errors_for(:messages => { :expiration_year => "Expiration year is unsupported" }).
|
30
|
+
should include("expiration_year is unsupported")
|
31
|
+
end
|
32
|
+
|
33
|
+
it "handles error results without a status" do
|
34
|
+
result = {}
|
35
|
+
errors = [ stub("error", :attribute => "foo", :message => "bar") ]
|
36
|
+
expect { Ashmont::Errors.new(result, errors).to_hash }.to_not raise_error(NoMethodError)
|
37
|
+
end
|
38
|
+
|
39
|
+
def errors_for(options = {})
|
40
|
+
result = stub("result",
|
41
|
+
:status => options[:status] || "rejected",
|
42
|
+
:processor_response_text => options[:processor_response_text] || "error")
|
43
|
+
errors = (options[:messages] || {}).map do |attribute, message|
|
44
|
+
stub("error", :attribute => attribute.to_s, :message => message)
|
45
|
+
end
|
46
|
+
|
47
|
+
Ashmont::Errors.new(result, errors).to_hash.inject([]) do |result, (attribute, message)|
|
48
|
+
result << [attribute, message].join(" ")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Ashmont::SubscribedCustomer do
|
4
|
+
it "delegates Customer methods to the customer" do
|
5
|
+
customer = stub("customer")
|
6
|
+
subscribed_customer = build_subscribed_customer(:customer => customer)
|
7
|
+
customer_methods = Ashmont::Customer.instance_methods(false)
|
8
|
+
merged_methods = [:errors, :save]
|
9
|
+
delegated_methods = customer_methods - merged_methods
|
10
|
+
delegated_methods.each do |method|
|
11
|
+
customer.stubs(method => "expected")
|
12
|
+
result = subscribed_customer.send(method, "argument")
|
13
|
+
customer.should have_received(method).with("argument")
|
14
|
+
result.should == "expected"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
it "delegates some Subscription methods to the subscription" do
|
19
|
+
subscription = stub("subscription")
|
20
|
+
subscribed_customer = build_subscribed_customer(:subscription => subscription)
|
21
|
+
%w(reload status next_billing_date transactions most_recent_transaction retry_charge past_due?).each do |method|
|
22
|
+
subscription.stubs(method => "expected")
|
23
|
+
result = subscribed_customer.send(method, "argument")
|
24
|
+
subscription.should have_received(method).with("argument")
|
25
|
+
result.should == "expected"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it "delegates #subscription_token to its subscription's token" do
|
30
|
+
subscription = stub("subscription", :token => "expected")
|
31
|
+
subscribed_customer = build_subscribed_customer(:subscription => subscription)
|
32
|
+
subscribed_customer.subscription_token.should == "expected"
|
33
|
+
end
|
34
|
+
|
35
|
+
it "#reloads the subscription" do
|
36
|
+
subscription = stub("subscription", :reload => "expected")
|
37
|
+
subscribed_customer = build_subscribed_customer(:subscription => subscription)
|
38
|
+
|
39
|
+
result = subscribed_customer.reload
|
40
|
+
|
41
|
+
subscription.should have_received(:reload)
|
42
|
+
result.should == "expected"
|
43
|
+
end
|
44
|
+
|
45
|
+
it "can #save the customer" do
|
46
|
+
attributes = { :email => "somebody@example.com" }
|
47
|
+
customer = stub("customer", :save => true, :token => nil)
|
48
|
+
subscribed_customer = build_subscribed_customer(:customer => customer)
|
49
|
+
|
50
|
+
result = subscribed_customer.save(attributes)
|
51
|
+
|
52
|
+
customer.should have_received(:save).with(attributes)
|
53
|
+
result.should be_true
|
54
|
+
end
|
55
|
+
|
56
|
+
it "saves a new customer without attributes" do
|
57
|
+
customer = stub("customer", :token => nil, :save => true)
|
58
|
+
subscribed_customer = build_subscribed_customer(:customer => customer)
|
59
|
+
|
60
|
+
subscribed_customer.save({})
|
61
|
+
|
62
|
+
customer.should have_received(:save).with({})
|
63
|
+
end
|
64
|
+
|
65
|
+
it "doesn't #save the customer without any customer attributes" do
|
66
|
+
attributes = { :price => 49 }
|
67
|
+
customer = stub("customer", :save => true, :token => "xyz")
|
68
|
+
subscribed_customer = build_subscribed_customer(:customer => customer)
|
69
|
+
|
70
|
+
subscribed_customer.save(attributes)
|
71
|
+
|
72
|
+
customer.should have_received(:save).never
|
73
|
+
end
|
74
|
+
|
75
|
+
it "can #save the subscription" do
|
76
|
+
attributes = { :plan_id => 41, :price => 15 }
|
77
|
+
subscription = stub("subscription", :save => "expected", :past_due? => false)
|
78
|
+
payment_method_token = "xyz"
|
79
|
+
customer = stub("customer", :payment_method_token => payment_method_token, :token => "xyz")
|
80
|
+
subscribed_customer = build_subscribed_customer(:subscription => subscription, :customer => customer)
|
81
|
+
|
82
|
+
result = subscribed_customer.save(attributes)
|
83
|
+
|
84
|
+
subscription.should have_received(:save).with(:plan_id => 41, :price => "15", :payment_method_token => payment_method_token)
|
85
|
+
result.should == "expected"
|
86
|
+
end
|
87
|
+
|
88
|
+
it "retries the subscription when past due" do
|
89
|
+
subscription = stub("subscription", :past_due? => true, :retry_charge => true)
|
90
|
+
|
91
|
+
subscribed_customer = build_subscribed_customer(:subscription => subscription)
|
92
|
+
subscribed_customer.save({})
|
93
|
+
|
94
|
+
subscription.should have_received(:retry_charge)
|
95
|
+
end
|
96
|
+
|
97
|
+
it "merges #errors from the customer and subscription" do
|
98
|
+
subscription = stub("subscription", :errors => stub_errors("one" => "first"))
|
99
|
+
customer = stub("customer", :errors => stub_errors("two" => "second"))
|
100
|
+
subscribed_customer = build_subscribed_customer(:subscription => subscription, :customer => customer)
|
101
|
+
|
102
|
+
subscribed_customer.errors.to_hash.should == { "one" => "first", "two" => "second" }
|
103
|
+
end
|
104
|
+
|
105
|
+
def build_subscribed_customer(options = {})
|
106
|
+
Ashmont::SubscribedCustomer.new(
|
107
|
+
options[:customer] || build_customer,
|
108
|
+
options[:subscription] || build_subscription
|
109
|
+
)
|
110
|
+
end
|
111
|
+
|
112
|
+
def build_customer
|
113
|
+
Ashmont::Customer.new("xyz")
|
114
|
+
end
|
115
|
+
|
116
|
+
def build_subscription
|
117
|
+
Ashmont::Subscription.new("abc", :status => "Active")
|
118
|
+
end
|
119
|
+
|
120
|
+
def stub_errors(messages)
|
121
|
+
stub("errors", :to_hash => messages)
|
122
|
+
end
|
123
|
+
end
|