ashmont 0.0.12
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.
- 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
|