spree_affirm 0.2.3

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.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/Gemfile +19 -0
  4. data/LICENSE +29 -0
  5. data/README.md +51 -0
  6. data/Rakefile +15 -0
  7. data/Versionfile +5 -0
  8. data/app/assets/javascripts/spree/backend/spree_affirm.js +3 -0
  9. data/app/assets/javascripts/spree/frontend/spree_affirm.js +2 -0
  10. data/app/assets/stylesheets/spree/backend/spree_affirm.css +4 -0
  11. data/app/assets/stylesheets/spree/frontend/spree_affirm.css +4 -0
  12. data/app/controllers/spree/affirm_controller.rb +68 -0
  13. data/app/models/spree/affirm_checkout.rb +38 -0
  14. data/app/models/spree/gateway/affirm.rb +51 -0
  15. data/app/views/spree/admin/log_entries/_affirm.html.erb +4 -0
  16. data/app/views/spree/admin/log_entries/index.html.erb +28 -0
  17. data/app/views/spree/admin/payments/source_forms/_affirm.html.erb +19 -0
  18. data/app/views/spree/admin/payments/source_views/_affirm.html.erb +12 -0
  19. data/app/views/spree/checkout/payment/_affirm.html.erb +195 -0
  20. data/bin/rails +7 -0
  21. data/config/locales/en.yml +29 -0
  22. data/config/routes.rb +5 -0
  23. data/db/migrate/20140514194315_create_affirm_checkout.rb +10 -0
  24. data/lib/active_merchant/billing/affirm.rb +161 -0
  25. data/lib/generators/spree_affirm/install/install_generator.rb +21 -0
  26. data/lib/spree_affirm/engine.rb +27 -0
  27. data/lib/spree_affirm/factories/affirm_checkout_factory.rb +211 -0
  28. data/lib/spree_affirm/factories/affirm_payment_method_factory.rb +8 -0
  29. data/lib/spree_affirm/factories/payment_factory.rb +10 -0
  30. data/lib/spree_affirm/factories.rb +5 -0
  31. data/lib/spree_affirm/version.rb +3 -0
  32. data/lib/spree_affirm.rb +2 -0
  33. data/spec/controllers/affirm_controller_spec.rb +138 -0
  34. data/spec/lib/active_merchant/billing/affirm_spec.rb +294 -0
  35. data/spec/models/affirm_address_validator_spec.rb +13 -0
  36. data/spec/models/spree_affirm_checkout_spec.rb +328 -0
  37. data/spec/models/spree_gateway_affirm_spec.rb +134 -0
  38. data/spec/spec_helper.rb +98 -0
  39. data/spree_affirm.gemspec +30 -0
  40. metadata +190 -0
@@ -0,0 +1,294 @@
1
+ require 'spec_helper'
2
+
3
+
4
+ describe ActiveMerchant::Billing::Affirm do
5
+ let(:affirm_payment) { FactoryGirl.create(:affirm_payment) }
6
+ let(:charge_id) { "1234-5678-9012" }
7
+
8
+
9
+ def expect_request(method, url_regexp, data, successful_response=true, response={})
10
+ affirm_payment.payment_method.provider.should_receive(:ssl_request) { |_method, _url, _data, _headers|
11
+
12
+ # check method type
13
+ _method.should be(method)
14
+
15
+ # test path
16
+ _url.should match(url_regexp) unless url_regexp.nil?
17
+
18
+ # test data
19
+ _data.should eq(data.to_json) unless data.nil?
20
+
21
+ # create response
22
+ _response = (response || {}).reverse_merge({
23
+ id: charge_id,
24
+ pending: true,
25
+ amount: 8000
26
+ })
27
+
28
+ _response[:status_code] = 400 unless successful_response
29
+
30
+ _response.to_json
31
+ }.at_least(1).times
32
+ end
33
+
34
+
35
+ def expect_request_and_return_success(method, url_regexp, data, response=nil )
36
+ expect_request(method, url_regexp, data, true, response)
37
+ end
38
+
39
+
40
+ def expect_request_and_return_failure(method, url_regexp, data, response=nil )
41
+ expect_request(method, url_regexp, data, false, response)
42
+ end
43
+
44
+
45
+ def expect_post_and_return_success(url_regexp=nil, data=nil, response=nil )
46
+ expect_request_and_return_success(:post, url_regexp, data, response)
47
+ end
48
+
49
+
50
+ def expect_post_and_return_failure(url_regexp=nil, data=nil, response=nil )
51
+ expect_request_and_return_failure(:post, url_regexp, data, response)
52
+ end
53
+
54
+
55
+ def expect_get_and_return_success(url_regexp=nil, data=nil, response=nil )
56
+ expect_request_and_return_success(:get, url_regexp, data, response)
57
+ end
58
+
59
+
60
+ def expect_get_and_return_failure(url_regexp=nil, data=nil, response=nil )
61
+ expect_request_and_return_failure(:get, url_regexp, data, response)
62
+ end
63
+
64
+
65
+
66
+ describe "#authorize" do
67
+ it "sends a POST to /api/v2/charges/ with the checkout_token" do
68
+ expect_post_and_return_success(/\/api\/v2\/charges/, {checkout_token: affirm_payment.source.token}, {amount: 8000})
69
+ affirm_payment.payment_method.provider.authorize(8000, affirm_payment.source)
70
+ end
71
+
72
+
73
+ context "when the POST response is not successful" do
74
+ it "returns the result from the POST" do
75
+ expect_post_and_return_failure nil, nil, {message: "Whoops!"}
76
+ result = affirm_payment.payment_method.provider.authorize(8000, affirm_payment.source)
77
+ expect(result.success?).to be(false)
78
+ expect(result.message).to eq("Whoops!")
79
+ end
80
+ end
81
+
82
+
83
+ context "when the POST respone is successful" do
84
+ context "when the auth amount does not match the given amount" do
85
+ it "returns an error response for that error" do
86
+ expect_post_and_return_success(/\/api\/v2\/charges/, {checkout_token: affirm_payment.source.token}, {amount: 9000})
87
+ result = affirm_payment.payment_method.provider.authorize(1999, affirm_payment.source)
88
+ expect(result.success?).to be(false)
89
+ expect(result.message).to eq("Auth amount does not match charge amount")
90
+ end
91
+ end
92
+
93
+
94
+ context "when the charge is not pending in the response" do
95
+ it "returns an error response for that error" do
96
+ expect_post_and_return_success(/\/api\/v2\/charges/, {checkout_token: affirm_payment.source.token}, {amount: 9000, pending: false})
97
+ result = affirm_payment.payment_method.provider.authorize(9000, affirm_payment.source)
98
+ expect(result.success?).to be(false)
99
+ expect(result.message).to eq("There was an error authorizing this Charge")
100
+ end
101
+ end
102
+
103
+
104
+ it "returns the result from the POST" do
105
+ expect_post_and_return_success(/\/api\/v2\/charges/, {checkout_token: affirm_payment.source.token}, {amount: 9000})
106
+ result = affirm_payment.payment_method.provider.authorize(9000, affirm_payment.source)
107
+ expect(result.success?).to be(true)
108
+ expect(result.params['amount']).to eq(9000)
109
+ end
110
+ end
111
+ end
112
+
113
+
114
+
115
+ describe "#purchase" do
116
+ it "authorizes the charge" do
117
+ expect_post_and_return_failure(/\/api\/v2\/charges/, {checkout_token: affirm_payment.source.token})
118
+ affirm_payment.payment_method.provider.purchase(8000, affirm_payment.source)
119
+ end
120
+
121
+
122
+ context "when the authorize response is not successful" do
123
+ it "returns the response of the auth response" do
124
+ expect_post_and_return_failure(/\/api\/v2\/charges/, {checkout_token: affirm_payment.source.token})
125
+ purchase_result = affirm_payment.payment_method.provider.purchase(8000, affirm_payment.source)
126
+ auth_result = affirm_payment.payment_method.provider.authorize(8000, affirm_payment.source)
127
+
128
+ [:success?, :params, :message].each do |method|
129
+ expect(purchase_result.send(method)).to eq(auth_result.send(method))
130
+ end
131
+ end
132
+
133
+
134
+ it "does not attempt to capture the charge" do
135
+ expect_post_and_return_failure(/\/api\/v2\/charges/, {checkout_token: affirm_payment.source.token})
136
+ affirm_payment.payment_method.provider.should_not_receive(:capture)
137
+ affirm_payment.payment_method.provider.purchase(8000, affirm_payment.source)
138
+ end
139
+ end
140
+
141
+
142
+ context "when the authorize response is successful" do
143
+ it "captures the charge" do
144
+ expect_post_and_return_success(/\/api\/v2\/charges/, {checkout_token: affirm_payment.source.token})
145
+ affirm_payment.payment_method.provider.should_receive(:capture)
146
+ affirm_payment.payment_method.provider.purchase(8000, affirm_payment.source)
147
+ end
148
+ end
149
+ end
150
+
151
+
152
+
153
+
154
+ describe "#capture" do
155
+ it "calls a POST to charges/[charge_ari]/capture" do
156
+ expect_post_and_return_success(/\/api\/v2\/charges\/#{charge_id}\/capture/, {amount: "8000"})
157
+ affirm_payment.payment_method.provider.capture(8000, charge_id)
158
+ end
159
+
160
+ context "when the capture response is not successful" do
161
+ it "returns the response" do
162
+ expect_post_and_return_failure(/\/api\/v2\/charges\/#{charge_id}\/capture/, {amount: "8000"},
163
+ message: "buuuuuusted"
164
+ )
165
+ result = affirm_payment.payment_method.provider.capture(8000, charge_id)
166
+ expect(result.success?).to be(false)
167
+ expect(result.message).to eq("buuuuuusted")
168
+ end
169
+ end
170
+
171
+
172
+ context "when the capture response is successful" do
173
+ it "returns the response" do
174
+ expect_post_and_return_success(/\/api\/v2\/charges\/#{charge_id}\/capture/, {amount: "8000"},
175
+ amount: 8000
176
+ )
177
+ result = affirm_payment.payment_method.provider.capture(8000, charge_id)
178
+ expect(result.success?).to be(true)
179
+ expect(result.params['amount']).to eq(8000)
180
+ end
181
+
182
+
183
+ context "when the captured amount does not equal the requested amount" do
184
+ it "returns a failed response" do
185
+ expect_post_and_return_success(/\/api\/v2\/charges\/#{charge_id}\/capture/, {amount: "8000"},
186
+ amount: 299
187
+ )
188
+ result = affirm_payment.payment_method.provider.capture(8000, charge_id)
189
+ expect(result.success?).to be(false)
190
+ expect(result.message).to eq("Capture amount does not match charge amount")
191
+ end
192
+ end
193
+ end
194
+ end
195
+
196
+
197
+
198
+ describe "#void" do
199
+ it "calls POST on /charges/[charge_ari]/void" do
200
+ expect_post_and_return_success(/\/api\/v2\/charges\/#{charge_id}\/void/)
201
+ affirm_payment.payment_method.provider.void(charge_id)
202
+ end
203
+
204
+
205
+ it "returns the response from the POST request" do
206
+ expect_post_and_return_success(/\/api\/v2\/charges\/#{charge_id}\/void/)
207
+ result = affirm_payment.payment_method.provider.void(charge_id)
208
+ expect(result.success?).to be(true)
209
+ expect(result.message).to eq("Transaction approved")
210
+ end
211
+ end
212
+
213
+
214
+
215
+ describe "#refund" do
216
+ it "calls POST on /charges/[charge_ari]/refund" do
217
+ expect_post_and_return_success(/\/api\/v2\/charges\/#{charge_id}\/refund/, {amount: "8000"})
218
+ affirm_payment.payment_method.provider.refund(8000, charge_id)
219
+ end
220
+
221
+
222
+ it "returns the response from the POST request" do
223
+ expect_post_and_return_success(/\/api\/v2\/charges\/#{charge_id}\/refund/, {amount: "8000"})
224
+ result = affirm_payment.payment_method.provider.refund(8000, charge_id)
225
+ expect(result.success?).to be(true)
226
+ expect(result.message).to eq("Transaction approved")
227
+ end
228
+ end
229
+
230
+
231
+
232
+ describe "#credit" do
233
+ context "when the requested amount is non zero" do
234
+ it "calls refund with the requested amount" do
235
+ affirm_payment.payment_method.provider.should_receive(:refund).with(8000, charge_id, {})
236
+ affirm_payment.payment_method.provider.credit(8000, charge_id)
237
+ end
238
+ end
239
+
240
+ context "when the requested amount is zero" do
241
+ it "returns a valid response and does not call refund()" do
242
+ affirm_payment.payment_method.provider.should_not_receive(:refund)
243
+ result = affirm_payment.payment_method.provider.credit(0, charge_id)
244
+ expect(result.success?).to be(true)
245
+ end
246
+ end
247
+ end
248
+
249
+
250
+
251
+ describe "#get_checkout" do
252
+ it "makes a GET request to /checkout/[checkout_token]" do
253
+ expect_get_and_return_success(/\/api\/v2\/checkout\/#{affirm_payment.source.token}/)
254
+ affirm_payment.payment_method.provider.get_checkout(affirm_payment.source.token)
255
+ end
256
+ end
257
+
258
+
259
+ describe "#commit" do
260
+ context "when a ResponseError is returned" do
261
+ it "returns an invalid response error" do
262
+ http_response = double()
263
+ http_response.stub(:code).and_return('400')
264
+ http_response.stub(:body).and_return("{}")
265
+ affirm_payment.payment_method.provider.should_receive(:ssl_request).and_raise ActiveMerchant::ResponseError.new(http_response)
266
+ result = affirm_payment.payment_method.provider.commit(:post, "test")
267
+ expect(result.success?).to be(false)
268
+ end
269
+
270
+ context "when the error response has malformed json" do
271
+ it "returns an invalid response error" do
272
+ http_response = double()
273
+ http_response.stub(:code).and_return('400')
274
+ http_response.stub(:body).and_return("{///xdf2fas!!+")
275
+ affirm_payment.payment_method.provider.should_receive(:parse).and_raise JSON::ParserError
276
+ affirm_payment.payment_method.provider.should_receive(:ssl_request).and_raise ActiveMerchant::ResponseError.new(http_response)
277
+ result = affirm_payment.payment_method.provider.commit(:post, "test")
278
+ expect(result.success?).to be(false)
279
+ expect(result.params['error']['message']).to match(/The raw response returned by the API was/)
280
+ end
281
+ end
282
+ end
283
+
284
+
285
+ context "when malformed JSON is returned" do
286
+ it "returns an invalid response error" do
287
+ affirm_payment.payment_method.provider.should_receive(:ssl_request).and_raise JSON::ParserError
288
+ result = affirm_payment.payment_method.provider.commit(:post, "test")
289
+ expect(result.success?).to be(false)
290
+ expect(result.params['error']['message']).to match(/The raw response returned by the API was/)
291
+ end
292
+ end
293
+ end
294
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Affirm::AddressValidator do
4
+ it 'detects when region1_code is missing' do
5
+ input_addr = {
6
+ state: 'California for example'
7
+ }
8
+ output = Affirm::AddressValidator.normalize_affirm_address(
9
+ input_addr)
10
+ expect(output['region1_code']).to eq(input_addr['state'])
11
+ end
12
+ end
13
+
@@ -0,0 +1,328 @@
1
+ require 'spec_helper'
2
+
3
+
4
+ describe Spree::AffirmCheckout do
5
+ let(:valid_checkout) { FactoryGirl.create(:affirm_checkout) }
6
+ let(:affirm_payment) { FactoryGirl.create(:affirm_payment) }
7
+
8
+
9
+ describe "scopes" do
10
+ describe "with_payment_profile" do
11
+ it "returns all" do
12
+ expect(Spree::AffirmCheckout.all).to eq(Spree::AffirmCheckout.with_payment_profile)
13
+ end
14
+ end
15
+
16
+
17
+ end
18
+
19
+
20
+ describe '#details' do
21
+ it "calls get_checkout from the payment provider exactly once" do
22
+ _checkout = FactoryGirl.build(:affirm_checkout, stub_details: false)
23
+ _checkout.payment_method.provider.stub(:get_checkout) do
24
+ {"hello" => "there"}
25
+ end
26
+ expect(_checkout.payment_method.provider).to receive(:get_checkout).exactly(1).times
27
+ _checkout.details
28
+ _checkout.details
29
+ _checkout.details
30
+ end
31
+ end
32
+
33
+
34
+ describe "#valid?" do
35
+ context "with all valid checkout details" do
36
+ it "should return true" do
37
+ expect(valid_checkout.valid?).to be(true)
38
+ end
39
+ end
40
+ end
41
+
42
+ describe "#check_valid_products" do
43
+ context "with all matching fields" do
44
+ it "does not set an error" do
45
+ valid_checkout.check_valid_products
46
+ expect(valid_checkout.errors.size).to be(0)
47
+ end
48
+
49
+ it "does not throw an error for case senstive name mismatches" do
50
+ _checkout = FactoryGirl.build(:affirm_checkout, full_name_case_mismatch: true)
51
+ _checkout.check_matching_billing_address
52
+ expect(_checkout.errors.size).to be(0)
53
+
54
+ end
55
+ end
56
+
57
+ context "with an extra product is in the checkout details" do
58
+ it "sets an error on line_items" do
59
+ _checkout = FactoryGirl.build(:affirm_checkout, extra_line_item: true )
60
+ _checkout.check_valid_products
61
+ expect(_checkout.errors[:line_items]).to_not be_empty
62
+ end
63
+ end
64
+
65
+
66
+ context "with the checkout details are missing a product" do
67
+ it "sets an error on line_items" do
68
+ _checkout = FactoryGirl.build(:affirm_checkout, missing_line_item: true )
69
+ _checkout.check_valid_products
70
+ expect(_checkout.errors[:line_items]).to_not be_empty
71
+ end
72
+ end
73
+
74
+ context "with a line item has mismatched quantity" do
75
+ it "sets an error for the item" do
76
+ _checkout = FactoryGirl.build(:affirm_checkout, quantity_mismatch: true )
77
+ _checkout.check_valid_products
78
+ expect(_checkout.errors.size).to be(1)
79
+ end
80
+ end
81
+
82
+ context "with a line item has mismatched price" do
83
+ it "sets an error for the item" do
84
+ _checkout = FactoryGirl.build(:affirm_checkout, price_mismatch: true )
85
+ _checkout.check_valid_products
86
+ expect(_checkout.errors.size).to be(1)
87
+ end
88
+ end
89
+
90
+ end
91
+
92
+ describe "#check_matching_billing_address" do
93
+ context "with a matching billing address" do
94
+ it "does not set any errors for the billing_address" do
95
+ valid_checkout.check_matching_billing_address
96
+ expect(valid_checkout.errors.size).to be(0)
97
+ expect(valid_checkout.errors[:billing_address]).to be_empty
98
+ end
99
+
100
+ context "with alternate address format" do
101
+ it "does not set any errors for the billing_address" do
102
+ _checkout = FactoryGirl.build(:affirm_checkout, alternate_billing_address_format: true)
103
+ valid_checkout.check_matching_billing_address
104
+ expect(valid_checkout.errors.size).to be(0)
105
+ expect(valid_checkout.errors[:billing_address]).to be_empty
106
+ end
107
+ end
108
+
109
+ context "with a name.full instead of first/last" do
110
+ it "does not set any error for the billing_address" do
111
+ _checkout = FactoryGirl.build(:affirm_checkout, billing_address_full_name: true)
112
+ _checkout.check_matching_billing_address
113
+ expect(_checkout.errors[:billing_address]).to be_empty
114
+ end
115
+ end
116
+ end
117
+
118
+ context "with a mismtached billing address" do
119
+ it "sets an error for the billing_address" do
120
+ _checkout = FactoryGirl.build(:affirm_checkout, billing_address_mismatch: true)
121
+ _checkout.check_matching_billing_address
122
+ expect(_checkout.errors[:billing_address]).not_to be_empty
123
+ end
124
+
125
+ context "with alternate address format" do
126
+ it "sets an error for the billing_address" do
127
+ _checkout = FactoryGirl.build(:affirm_checkout, billing_address_mismatch: true, alternate_billing_address_format: true)
128
+ _checkout.check_matching_billing_address
129
+ expect(_checkout.errors[:billing_address]).not_to be_empty
130
+ end
131
+ end
132
+
133
+
134
+ context "with a name.full instead of first/last" do
135
+ it "sets an error for the billing_address" do
136
+ _checkout = FactoryGirl.build(:affirm_checkout, billing_address_mismatch: true, billing_address_full_name: true)
137
+ _checkout.check_matching_billing_address
138
+ expect(_checkout.errors[:billing_address]).not_to be_empty
139
+ end
140
+ end
141
+ end
142
+ end
143
+
144
+
145
+
146
+ describe "#check_matching_shipping_address" do
147
+ context "with a matching shipping address" do
148
+ it "does not set an error for the shipping_address" do
149
+ valid_checkout.check_matching_shipping_address
150
+ expect(valid_checkout.errors[:shipping_address]).to be_empty
151
+ end
152
+ end
153
+
154
+
155
+ context "with a mismatched shipping address" do
156
+ it "adds an error for the shipping_address" do
157
+ _checkout = FactoryGirl.build(:affirm_checkout, shipping_address_mismatch: true)
158
+ _checkout.check_matching_shipping_address
159
+ expect(_checkout.errors[:shipping_address]).not_to be_empty
160
+ end
161
+ end
162
+ end
163
+
164
+
165
+ describe "#check_matching_billing_email" do
166
+ context "with a matching billing email" do
167
+ it "does not set an error for the billing_email" do
168
+ valid_checkout.check_matching_billing_email
169
+ expect(valid_checkout.errors[:billing_email]).to be_empty
170
+ end
171
+ end
172
+
173
+
174
+ context "with a mismatched billing email" do
175
+ it "adds an error for billing_email" do
176
+ _checkout = FactoryGirl.build(:affirm_checkout, billing_email_mismatch: true)
177
+ _checkout.check_matching_billing_email
178
+ expect(_checkout.errors[:billing_email]).not_to be_empty
179
+ end
180
+ end
181
+ end
182
+
183
+ describe "actions" do
184
+
185
+ describe "#actions" do
186
+ it "returns capture, void, and credit" do
187
+ expect(valid_checkout.actions).to eq(['capture', 'void', 'credit'])
188
+ end
189
+ end
190
+
191
+
192
+ describe "can_capture?" do
193
+ context "with a payment response code set" do
194
+ before(:each) { affirm_payment.response_code = "1234-1234" }
195
+
196
+ context "with a payment in pending state" do
197
+ before(:each) { affirm_payment.state = 'pending' }
198
+
199
+ it "returns true" do
200
+ expect(valid_checkout.can_capture?(affirm_payment)).to be(true)
201
+ end
202
+ end
203
+
204
+
205
+ context "with a payment in checkout state" do
206
+ before(:each) { affirm_payment.state = 'checkout' }
207
+
208
+ it "returns true" do
209
+ expect(valid_checkout.can_capture?(affirm_payment)).to be(true)
210
+ end
211
+ end
212
+
213
+
214
+ context "with a payment in complete state" do
215
+ before(:each) { affirm_payment.state = 'complete' }
216
+
217
+ it "returns false" do
218
+ expect(valid_checkout.can_capture?(affirm_payment)).to be(false)
219
+ end
220
+ end
221
+
222
+ end
223
+
224
+
225
+ context "with no response code set on the payment" do
226
+ before(:each) { affirm_payment.response_code = nil }
227
+
228
+ it "returns false" do
229
+ expect(valid_checkout.can_capture?(affirm_payment)).to be(false)
230
+ end
231
+ end
232
+ end
233
+
234
+
235
+ describe "can_void?" do
236
+ context "with a payment response code set" do
237
+ before(:each) { affirm_payment.response_code = "1234-1234" }
238
+
239
+ context "with a payment in pending state" do
240
+ before(:each) { affirm_payment.state = 'pending' }
241
+
242
+ it "returns true" do
243
+ expect(valid_checkout.can_void?(affirm_payment)).to be(true)
244
+ end
245
+ end
246
+
247
+ context "with a payment in checkout state" do
248
+ before(:each) { affirm_payment.state = 'checkout' }
249
+
250
+ it "returns false" do
251
+ expect(valid_checkout.can_void?(affirm_payment)).to be(false)
252
+ end
253
+ end
254
+
255
+
256
+ context "with a payment in complete state" do
257
+ before(:each) { affirm_payment.state = 'complete' }
258
+
259
+ it "returns false" do
260
+ expect(valid_checkout.can_void?(affirm_payment)).to be(false)
261
+ end
262
+ end
263
+ end
264
+
265
+
266
+ context "with no response code set on the payment" do
267
+ before(:each) { affirm_payment.response_code = nil }
268
+
269
+ it "returns false" do
270
+ expect(valid_checkout.can_void?(affirm_payment)).to be(false)
271
+ end
272
+ end
273
+ end
274
+
275
+
276
+
277
+ describe "can_credit?" do
278
+ context "when the payment has not been completed" do
279
+ before(:each) { affirm_payment.state = 'pending' }
280
+
281
+ it "returns false" do
282
+ expect(valid_checkout.can_credit?(affirm_payment)).to be(false)
283
+ end
284
+ end
285
+
286
+ context "when the payment's order state is not 'credit_owed'" do
287
+ before(:each) do
288
+ affirm_payment.state = 'completed'
289
+ affirm_payment.order.payment_state = 'completed'
290
+ end
291
+
292
+ it "returns false" do
293
+ expect(valid_checkout.can_credit?(affirm_payment)).to be(false)
294
+ end
295
+ end
296
+
297
+ context "when the payement's order state is 'credit_owed'" do
298
+ before(:each) { affirm_payment.order.payment_state = 'credit_owed' }
299
+
300
+ context "when the payment has been completed" do
301
+ before(:each) { affirm_payment.state = 'completed'}
302
+
303
+ context "when the payment credit_allowed is greater than 0" do
304
+ before(:each) do
305
+ affirm_payment.stub(:credit_allowed).and_return 100
306
+ end
307
+
308
+ it "returns true" do
309
+ expect(valid_checkout.can_credit?(affirm_payment)).to be(true)
310
+ end
311
+ end
312
+
313
+
314
+ context "when the payment credit_allowed is equal to 0" do
315
+ before(:each) do
316
+ affirm_payment.stub(:credit_allowed).and_return 0
317
+ end
318
+
319
+ it "returns false" do
320
+ expect(valid_checkout.can_credit?(affirm_payment)).to be(false)
321
+ end
322
+ end
323
+ end
324
+ end
325
+
326
+ end
327
+ end
328
+ end