spree_core 3.0.5 → 3.0.6

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 (194) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/Gemfile +3 -0
  4. data/Rakefile +30 -0
  5. data/app/assets/javascripts/spree.js.coffee.erb +1 -1
  6. data/app/models/spree/ability.rb +1 -1
  7. data/app/models/spree/base.rb +3 -1
  8. data/app/models/spree/order_updater.rb +2 -1
  9. data/app/models/spree/price.rb +7 -12
  10. data/app/models/spree/product.rb +3 -2
  11. data/app/models/spree/reimbursement.rb +1 -1
  12. data/app/models/spree/state.rb +2 -0
  13. data/app/models/spree/zone.rb +1 -1
  14. data/lib/spree/core/version.rb +1 -1
  15. data/lib/spree/testing_support/shoulda_matcher_configuration.rb +6 -0
  16. data/script/rails +9 -0
  17. data/spec/fixtures/thinking-cat.jpg +0 -0
  18. data/spec/helpers/base_helper_spec.rb +137 -0
  19. data/spec/helpers/products_helper_spec.rb +224 -0
  20. data/spec/lib/calculated_adjustments_spec.rb +7 -0
  21. data/spec/lib/i18n_spec.rb +123 -0
  22. data/spec/lib/search/base_spec.rb +86 -0
  23. data/spec/lib/spree/core/controller_helpers/auth_spec.rb +101 -0
  24. data/spec/lib/spree/core/controller_helpers/order_spec.rb +95 -0
  25. data/spec/lib/spree/core/controller_helpers/search_spec.rb +17 -0
  26. data/spec/lib/spree/core/controller_helpers/store_spec.rb +16 -0
  27. data/spec/lib/spree/core/controller_helpers/strong_parameters_spec.rb +39 -0
  28. data/spec/lib/spree/core/delegate_belongs_to_spec.rb +22 -0
  29. data/spec/lib/spree/core/importer/order_spec.rb +502 -0
  30. data/spec/lib/spree/core/validators/email_spec.rb +53 -0
  31. data/spec/lib/spree/localized_number_spec.rb +38 -0
  32. data/spec/lib/spree/migrations_spec.rb +34 -0
  33. data/spec/lib/spree/money_spec.rb +122 -0
  34. data/spec/lib/tasks/exchanges_spec.rb +136 -0
  35. data/spec/mailers/order_mailer_spec.rb +124 -0
  36. data/spec/mailers/reimbursement_mailer_spec.rb +47 -0
  37. data/spec/mailers/shipment_mailer_spec.rb +63 -0
  38. data/spec/mailers/test_mailer_spec.rb +24 -0
  39. data/spec/models/spree/ability_spec.rb +246 -0
  40. data/spec/models/spree/address_spec.rb +291 -0
  41. data/spec/models/spree/adjustable/adjustments_updater_spec.rb +286 -0
  42. data/spec/models/spree/adjustment_spec.rb +163 -0
  43. data/spec/models/spree/app_configuration_spec.rb +23 -0
  44. data/spec/models/spree/asset_spec.rb +25 -0
  45. data/spec/models/spree/calculator/default_tax_spec.rb +127 -0
  46. data/spec/models/spree/calculator/flat_percent_item_total_spec.rb +25 -0
  47. data/spec/models/spree/calculator/flat_rate_spec.rb +47 -0
  48. data/spec/models/spree/calculator/flexi_rate_spec.rb +41 -0
  49. data/spec/models/spree/calculator/percent_on_line_item_spec.rb +15 -0
  50. data/spec/models/spree/calculator/price_sack_spec.rb +30 -0
  51. data/spec/models/spree/calculator/refunds/default_refund_amount_spec.rb +51 -0
  52. data/spec/models/spree/calculator/shipping.rb +8 -0
  53. data/spec/models/spree/calculator/shipping/flat_percent_item_total_spec.rb +23 -0
  54. data/spec/models/spree/calculator/shipping/flat_rate_spec.rb +13 -0
  55. data/spec/models/spree/calculator/shipping/flexi_rate_spec.rb +52 -0
  56. data/spec/models/spree/calculator/shipping/per_item_spec.rb +20 -0
  57. data/spec/models/spree/calculator/shipping/price_sack_spec.rb +29 -0
  58. data/spec/models/spree/calculator/tiered_flat_rate_spec.rb +40 -0
  59. data/spec/models/spree/calculator/tiered_percent_spec.rb +51 -0
  60. data/spec/models/spree/calculator_spec.rb +69 -0
  61. data/spec/models/spree/classification_spec.rb +93 -0
  62. data/spec/models/spree/concerns/display_money_spec.rb +43 -0
  63. data/spec/models/spree/country_spec.rb +18 -0
  64. data/spec/models/spree/credit_card_spec.rb +324 -0
  65. data/spec/models/spree/customer_return_spec.rb +262 -0
  66. data/spec/models/spree/exchange_spec.rb +75 -0
  67. data/spec/models/spree/gateway/bogus_simple.rb +20 -0
  68. data/spec/models/spree/gateway/bogus_spec.rb +13 -0
  69. data/spec/models/spree/gateway_spec.rb +54 -0
  70. data/spec/models/spree/image_spec.rb +5 -0
  71. data/spec/models/spree/inventory_unit_spec.rb +242 -0
  72. data/spec/models/spree/line_item_spec.rb +267 -0
  73. data/spec/models/spree/option_type_spec.rb +14 -0
  74. data/spec/models/spree/option_value_spec.rb +13 -0
  75. data/spec/models/spree/order/address_spec.rb +50 -0
  76. data/spec/models/spree/order/adjustments_spec.rb +29 -0
  77. data/spec/models/spree/order/callbacks_spec.rb +42 -0
  78. data/spec/models/spree/order/checkout_spec.rb +764 -0
  79. data/spec/models/spree/order/currency_updater_spec.rb +32 -0
  80. data/spec/models/spree/order/finalizing_spec.rb +117 -0
  81. data/spec/models/spree/order/helpers_spec.rb +5 -0
  82. data/spec/models/spree/order/payment_spec.rb +214 -0
  83. data/spec/models/spree/order/risk_assessment_spec.rb +84 -0
  84. data/spec/models/spree/order/shipments_spec.rb +43 -0
  85. data/spec/models/spree/order/state_machine_spec.rb +216 -0
  86. data/spec/models/spree/order/tax_spec.rb +84 -0
  87. data/spec/models/spree/order/totals_spec.rb +24 -0
  88. data/spec/models/spree/order/updating_spec.rb +18 -0
  89. data/spec/models/spree/order/validations_spec.rb +15 -0
  90. data/spec/models/spree/order_contents_spec.rb +256 -0
  91. data/spec/models/spree/order_inventory_spec.rb +228 -0
  92. data/spec/models/spree/order_merger_spec.rb +133 -0
  93. data/spec/models/spree/order_spec.rb +954 -0
  94. data/spec/models/spree/order_updater_spec.rb +283 -0
  95. data/spec/models/spree/payment/gateway_options_spec.rb +119 -0
  96. data/spec/models/spree/payment_method_spec.rb +95 -0
  97. data/spec/models/spree/payment_spec.rb +926 -0
  98. data/spec/models/spree/preference_spec.rb +80 -0
  99. data/spec/models/spree/preferences/configuration_spec.rb +30 -0
  100. data/spec/models/spree/preferences/preferable_spec.rb +348 -0
  101. data/spec/models/spree/preferences/scoped_store_spec.rb +58 -0
  102. data/spec/models/spree/preferences/store_spec.rb +46 -0
  103. data/spec/models/spree/price_spec.rb +42 -0
  104. data/spec/models/spree/product/scopes_spec.rb +148 -0
  105. data/spec/models/spree/product_duplicator_spec.rb +103 -0
  106. data/spec/models/spree/product_filter_spec.rb +26 -0
  107. data/spec/models/spree/product_option_type_spec.rb +5 -0
  108. data/spec/models/spree/product_property_spec.rb +11 -0
  109. data/spec/models/spree/product_spec.rb +474 -0
  110. data/spec/models/spree/promotion/actions/create_adjustment_spec.rb +50 -0
  111. data/spec/models/spree/promotion/actions/create_item_adjustments_spec.rb +148 -0
  112. data/spec/models/spree/promotion/actions/create_line_items_spec.rb +86 -0
  113. data/spec/models/spree/promotion/actions/free_shipping_spec.rb +36 -0
  114. data/spec/models/spree/promotion/rules/first_order_spec.rb +75 -0
  115. data/spec/models/spree/promotion/rules/item_total_spec.rb +282 -0
  116. data/spec/models/spree/promotion/rules/one_use_per_user_spec.rb +42 -0
  117. data/spec/models/spree/promotion/rules/option_value_spec.rb +90 -0
  118. data/spec/models/spree/promotion/rules/product_spec.rb +143 -0
  119. data/spec/models/spree/promotion/rules/taxon_spec.rb +102 -0
  120. data/spec/models/spree/promotion/rules/user_logged_in_spec.rb +27 -0
  121. data/spec/models/spree/promotion/rules/user_spec.rb +37 -0
  122. data/spec/models/spree/promotion_action_spec.rb +10 -0
  123. data/spec/models/spree/promotion_category_spec.rb +17 -0
  124. data/spec/models/spree/promotion_handler/cart_spec.rb +102 -0
  125. data/spec/models/spree/promotion_handler/coupon_spec.rb +323 -0
  126. data/spec/models/spree/promotion_handler/free_shipping_spec.rb +48 -0
  127. data/spec/models/spree/promotion_handler/page_spec.rb +44 -0
  128. data/spec/models/spree/promotion_rule_spec.rb +29 -0
  129. data/spec/models/spree/promotion_spec.rb +603 -0
  130. data/spec/models/spree/property_spec.rb +5 -0
  131. data/spec/models/spree/prototype_spec.rb +5 -0
  132. data/spec/models/spree/refund_spec.rb +195 -0
  133. data/spec/models/spree/reimbursement/credit_spec.rb +36 -0
  134. data/spec/models/spree/reimbursement/reimbursement_type_engine_spec.rb +140 -0
  135. data/spec/models/spree/reimbursement/reimbursement_type_validator_spec.rb +83 -0
  136. data/spec/models/spree/reimbursement_performer_spec.rb +30 -0
  137. data/spec/models/spree/reimbursement_spec.rb +215 -0
  138. data/spec/models/spree/reimbursement_tax_calculator_spec.rb +51 -0
  139. data/spec/models/spree/reimbursement_type/credit_spec.rb +53 -0
  140. data/spec/models/spree/reimbursement_type/exchange_spec.rb +46 -0
  141. data/spec/models/spree/reimbursement_type/original_payment_spec.rb +55 -0
  142. data/spec/models/spree/return_authorization_spec.rb +250 -0
  143. data/spec/models/spree/return_item/eligibility_validator/default_spec.rb +77 -0
  144. data/spec/models/spree/return_item/eligibility_validator/inventory_shipped_spec.rb +58 -0
  145. data/spec/models/spree/return_item/eligibility_validator/no_reimbursements_spec.rb +61 -0
  146. data/spec/models/spree/return_item/eligibility_validator/order_completed_spec.rb +32 -0
  147. data/spec/models/spree/return_item/eligibility_validator/rma_required_spec.rb +29 -0
  148. data/spec/models/spree/return_item/eligibility_validator/time_since_purchase_spec.rb +35 -0
  149. data/spec/models/spree/return_item/exchange_variant_eligibility/same_option_value_spec.rb +65 -0
  150. data/spec/models/spree/return_item/exchange_variant_eligibility/same_product_spec.rb +43 -0
  151. data/spec/models/spree/return_item_spec.rb +682 -0
  152. data/spec/models/spree/returns_calculator_spec.rb +14 -0
  153. data/spec/models/spree/shipment_spec.rb +740 -0
  154. data/spec/models/spree/shipping_calculator_spec.rb +45 -0
  155. data/spec/models/spree/shipping_category_spec.rb +5 -0
  156. data/spec/models/spree/shipping_method_spec.rb +88 -0
  157. data/spec/models/spree/shipping_rate_spec.rb +141 -0
  158. data/spec/models/spree/state_spec.rb +18 -0
  159. data/spec/models/spree/stock/availability_validator_spec.rb +36 -0
  160. data/spec/models/spree/stock/content_item_spec.rb +22 -0
  161. data/spec/models/spree/stock/coordinator_spec.rb +51 -0
  162. data/spec/models/spree/stock/differentiator_spec.rb +39 -0
  163. data/spec/models/spree/stock/estimator_spec.rb +154 -0
  164. data/spec/models/spree/stock/inventory_unit_builder_spec.rb +38 -0
  165. data/spec/models/spree/stock/package_spec.rb +194 -0
  166. data/spec/models/spree/stock/packer_spec.rb +70 -0
  167. data/spec/models/spree/stock/prioritizer_spec.rb +125 -0
  168. data/spec/models/spree/stock/quantifier_spec.rb +97 -0
  169. data/spec/models/spree/stock/splitter/backordered_spec.rb +29 -0
  170. data/spec/models/spree/stock/splitter/base_spec.rb +21 -0
  171. data/spec/models/spree/stock/splitter/shipping_category_spec.rb +47 -0
  172. data/spec/models/spree/stock/splitter/weight_spec.rb +32 -0
  173. data/spec/models/spree/stock_item_spec.rb +410 -0
  174. data/spec/models/spree/stock_location_spec.rb +243 -0
  175. data/spec/models/spree/stock_movement_spec.rb +56 -0
  176. data/spec/models/spree/stock_transfer_spec.rb +50 -0
  177. data/spec/models/spree/store_spec.rb +50 -0
  178. data/spec/models/spree/tax_category_spec.rb +27 -0
  179. data/spec/models/spree/tax_rate_spec.rb +382 -0
  180. data/spec/models/spree/taxon_spec.rb +74 -0
  181. data/spec/models/spree/taxonomy_spec.rb +18 -0
  182. data/spec/models/spree/tracker_spec.rb +21 -0
  183. data/spec/models/spree/user_spec.rb +130 -0
  184. data/spec/models/spree/validations/db_maximum_length_validator_spec.rb +24 -0
  185. data/spec/models/spree/variant_spec.rb +523 -0
  186. data/spec/models/spree/zone_spec.rb +444 -0
  187. data/spec/spec_helper.rb +74 -0
  188. data/spec/support/big_decimal.rb +5 -0
  189. data/spec/support/concerns/adjustment_source_spec.rb +23 -0
  190. data/spec/support/concerns/default_price_spec.rb +28 -0
  191. data/spec/support/rake.rb +13 -0
  192. data/spec/support/test_gateway.rb +2 -0
  193. data/spree_core.gemspec +48 -0
  194. metadata +185 -4
@@ -0,0 +1,926 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::Payment, :type => :model do
4
+ let(:order) { Spree::Order.create }
5
+ let(:refund_reason) { create(:refund_reason) }
6
+
7
+ let(:gateway) do
8
+ gateway = Spree::Gateway::Bogus.create(active: true, name: 'Bogus')
9
+ allow(gateway).to receive_messages source_required: true
10
+ gateway
11
+ end
12
+
13
+ let(:avs_code) { 'D' }
14
+ let(:cvv_code) { 'M' }
15
+
16
+ let(:card) { create :credit_card }
17
+
18
+ let(:payment) do
19
+ payment = Spree::Payment.new
20
+ payment.source = card
21
+ payment.order = order
22
+ payment.payment_method = gateway
23
+ payment.amount = 5
24
+ payment
25
+ end
26
+
27
+ let(:amount_in_cents) { (payment.amount * 100).round }
28
+
29
+ let!(:success_response) do
30
+ ActiveMerchant::Billing::Response.new(true, '', {}, {
31
+ authorization: '123',
32
+ cvv_result: cvv_code,
33
+ avs_result: { code: avs_code }
34
+ })
35
+ end
36
+
37
+ let(:failed_response) do
38
+ ActiveMerchant::Billing::Response.new(false, '', {}, {})
39
+ end
40
+
41
+ before(:each) do
42
+ # So it doesn't create log entries every time a processing method is called
43
+ allow(payment.log_entries).to receive(:create!)
44
+ end
45
+
46
+ context '.risky' do
47
+
48
+ let!(:payment_1) { create(:payment, avs_response: 'Y', cvv_response_code: 'M', cvv_response_message: 'Match') }
49
+ let!(:payment_2) { create(:payment, avs_response: 'Y', cvv_response_code: 'M', cvv_response_message: '') }
50
+ let!(:payment_3) { create(:payment, avs_response: 'A', cvv_response_code: 'M', cvv_response_message: 'Match') }
51
+ let!(:payment_4) { create(:payment, avs_response: 'Y', cvv_response_code: 'N', cvv_response_message: 'No Match') }
52
+
53
+ it 'should not return successful responses' do
54
+ expect(subject.class.risky.to_a).to match_array([payment_3, payment_4])
55
+ end
56
+ end
57
+
58
+ context "#captured_amount" do
59
+ context "calculates based on capture events" do
60
+ it "with 0 capture events" do
61
+ expect(payment.captured_amount).to eq(0)
62
+ end
63
+
64
+ it "with some capture events" do
65
+ payment.save
66
+ payment.capture_events.create!(amount: 2.0)
67
+ payment.capture_events.create!(amount: 3.0)
68
+ expect(payment.captured_amount).to eq(5)
69
+ end
70
+ end
71
+ end
72
+
73
+ context '#uncaptured_amount' do
74
+ context "calculates based on capture events" do
75
+ it "with 0 capture events" do
76
+ expect(payment.uncaptured_amount).to eq(5.0)
77
+ end
78
+
79
+ it "with some capture events" do
80
+ payment.save
81
+ payment.capture_events.create!(amount: 2.0)
82
+ payment.capture_events.create!(amount: 3.0)
83
+ expect(payment.uncaptured_amount).to eq(0)
84
+ end
85
+ end
86
+ end
87
+
88
+ context 'validations' do
89
+ it "returns useful error messages when source is invalid" do
90
+ payment.source = Spree::CreditCard.new
91
+ expect(payment).not_to be_valid
92
+ cc_errors = payment.errors['Credit Card']
93
+ expect(cc_errors).to include("Number can't be blank")
94
+ expect(cc_errors).to include("Month is not a number")
95
+ expect(cc_errors).to include("Year is not a number")
96
+ expect(cc_errors).to include("Verification Value can't be blank")
97
+ end
98
+ end
99
+
100
+ # Regression test for https://github.com/spree/spree/pull/2224
101
+ context 'failure' do
102
+ it 'should transition to failed from pending state' do
103
+ payment.state = 'pending'
104
+ payment.failure
105
+ expect(payment.state).to eql('failed')
106
+ end
107
+
108
+ it 'should transition to failed from processing state' do
109
+ payment.state = 'processing'
110
+ payment.failure
111
+ expect(payment.state).to eql('failed')
112
+ end
113
+ end
114
+
115
+ context 'invalidate' do
116
+ it 'should transition from checkout to invalid' do
117
+ payment.state = 'checkout'
118
+ payment.invalidate
119
+ expect(payment.state).to eq('invalid')
120
+ end
121
+ end
122
+
123
+ context "processing" do
124
+ describe "#process!" do
125
+ it "should purchase if with auto_capture" do
126
+ expect(payment.payment_method).to receive(:auto_capture?).and_return(true)
127
+ payment.process!
128
+ expect(payment).to be_completed
129
+ end
130
+
131
+ it "should authorize without auto_capture" do
132
+ expect(payment.payment_method).to receive(:auto_capture?).and_return(false)
133
+ payment.process!
134
+ expect(payment).to be_pending
135
+ end
136
+
137
+ it "should make the state 'processing'" do
138
+ expect(payment).to receive(:started_processing!)
139
+ payment.process!
140
+ end
141
+
142
+ it "should invalidate if payment method doesnt support source" do
143
+ expect(payment.payment_method).to receive(:supports?).with(payment.source).and_return(false)
144
+ expect { payment.process!}.to raise_error(Spree::Core::GatewayError)
145
+ expect(payment.state).to eq('invalid')
146
+ end
147
+
148
+ # Regression test for #4598
149
+ it "should allow payments with a gateway_customer_profile_id" do
150
+ allow(payment.source).to receive_messages :gateway_customer_profile_id => "customer_1"
151
+ expect(payment.payment_method).to receive(:supports?).with(payment.source).and_return(false)
152
+ expect(payment).to receive(:started_processing!)
153
+ payment.process!
154
+ end
155
+
156
+ # Another regression test for #4598
157
+ it "should allow payments with a gateway_payment_profile_id" do
158
+ allow(payment.source).to receive_messages :gateway_payment_profile_id => "customer_1"
159
+ expect(payment.payment_method).to receive(:supports?).with(payment.source).and_return(false)
160
+ expect(payment).to receive(:started_processing!)
161
+ payment.process!
162
+ end
163
+ end
164
+
165
+ describe "#authorize!" do
166
+ it "should call authorize on the gateway with the payment amount" do
167
+ expect(payment.payment_method).to receive(:authorize).with(amount_in_cents,
168
+ card,
169
+ anything).and_return(success_response)
170
+ payment.authorize!
171
+ end
172
+
173
+ it "should call authorize on the gateway with the currency code" do
174
+ allow(payment).to receive_messages :currency => 'GBP'
175
+ expect(payment.payment_method).to receive(:authorize).with(amount_in_cents,
176
+ card,
177
+ hash_including({:currency => "GBP"})).and_return(success_response)
178
+ payment.authorize!
179
+ end
180
+
181
+ it "should log the response" do
182
+ payment.save!
183
+ expect(payment.log_entries).to receive(:create!).with(details: anything)
184
+ payment.authorize!
185
+ end
186
+
187
+ context "if successful" do
188
+ before do
189
+ expect(payment.payment_method).to receive(:authorize).with(amount_in_cents,
190
+ card,
191
+ anything).and_return(success_response)
192
+ end
193
+
194
+ it "should store the response_code, avs_response and cvv_response fields" do
195
+ payment.authorize!
196
+ expect(payment.response_code).to eq('123')
197
+ expect(payment.avs_response).to eq(avs_code)
198
+ expect(payment.cvv_response_code).to eq(cvv_code)
199
+ expect(payment.cvv_response_message).to eq(ActiveMerchant::Billing::CVVResult::MESSAGES[cvv_code])
200
+ end
201
+
202
+ it "should make payment pending" do
203
+ expect(payment).to receive(:pend!)
204
+ payment.authorize!
205
+ end
206
+ end
207
+
208
+ context "if unsuccessful" do
209
+ it "should mark payment as failed" do
210
+ allow(gateway).to receive(:authorize).and_return(failed_response)
211
+ expect(payment).to receive(:failure)
212
+ expect(payment).not_to receive(:pend)
213
+ expect {
214
+ payment.authorize!
215
+ }.to raise_error(Spree::Core::GatewayError)
216
+ end
217
+ end
218
+ end
219
+
220
+ describe "#purchase!" do
221
+ it "should call purchase on the gateway with the payment amount" do
222
+ expect(gateway).to receive(:purchase).with(amount_in_cents, card, anything).and_return(success_response)
223
+ payment.purchase!
224
+ end
225
+
226
+ it "should log the response" do
227
+ payment.save!
228
+ expect(payment.log_entries).to receive(:create!).with(details: anything)
229
+ payment.purchase!
230
+ end
231
+
232
+ context "if successful" do
233
+ before do
234
+ expect(payment.payment_method).to receive(:purchase).with(amount_in_cents,
235
+ card,
236
+ anything).and_return(success_response)
237
+ end
238
+
239
+ it "should store the response_code and avs_response" do
240
+ payment.purchase!
241
+ expect(payment.response_code).to eq('123')
242
+ expect(payment.avs_response).to eq(avs_code)
243
+ end
244
+
245
+ it "should make payment complete" do
246
+ expect(payment).to receive(:complete!)
247
+ payment.purchase!
248
+ end
249
+
250
+ it "should log a capture event" do
251
+ payment.purchase!
252
+ expect(payment.capture_events.count).to eq(1)
253
+ expect(payment.capture_events.first.amount).to eq(payment.amount)
254
+ end
255
+
256
+ it "should set the uncaptured amount to 0" do
257
+ payment.purchase!
258
+ expect(payment.uncaptured_amount).to eq(0)
259
+ end
260
+ end
261
+
262
+ context "if unsuccessful" do
263
+ before do
264
+ allow(gateway).to receive(:purchase).and_return(failed_response)
265
+ expect(payment).to receive(:failure)
266
+ expect(payment).not_to receive(:pend)
267
+ end
268
+
269
+ it "should make payment failed" do
270
+ expect { payment.purchase! }.to raise_error(Spree::Core::GatewayError)
271
+ end
272
+
273
+ it "should not log a capture event" do
274
+ expect { payment.purchase! }.to raise_error(Spree::Core::GatewayError)
275
+ expect(payment.capture_events.count).to eq(0)
276
+ end
277
+ end
278
+ end
279
+
280
+ describe "#capture!" do
281
+ context "when payment is pending" do
282
+ before do
283
+ payment.amount = 100
284
+ payment.state = 'pending'
285
+ payment.response_code = '12345'
286
+ end
287
+
288
+ context "if successful" do
289
+ context 'for entire amount' do
290
+ before do
291
+ expect(payment.payment_method).to receive(:capture).with(payment.display_amount.money.cents, payment.response_code, anything).and_return(success_response)
292
+ end
293
+
294
+ it "should make payment complete" do
295
+ expect(payment).to receive(:complete!)
296
+ payment.capture!
297
+ end
298
+
299
+ it "logs capture events" do
300
+ payment.capture!
301
+ expect(payment.capture_events.count).to eq(1)
302
+ expect(payment.capture_events.first.amount).to eq(payment.amount)
303
+ end
304
+ end
305
+
306
+ context 'for partial amount' do
307
+ let(:original_amount) { payment.money.money.cents }
308
+ let(:capture_amount) { original_amount - 100 }
309
+
310
+ before do
311
+ expect(payment.payment_method).to receive(:capture).with(capture_amount, payment.response_code, anything).and_return(success_response)
312
+ end
313
+
314
+ it "should make payment complete & create pending payment for remaining amount" do
315
+ expect(payment).to receive(:complete!)
316
+ payment.capture!(capture_amount)
317
+ order = payment.order
318
+ payments = order.payments
319
+
320
+ expect(payments.size).to eq 2
321
+ expect(payments.pending.first.amount).to eq 1
322
+ # Payment stays processing for spec because of receive(:complete!) stub.
323
+ expect(payments.processing.first.amount).to eq(capture_amount / 100)
324
+ expect(payments.processing.first.source).to eq(payments.pending.first.source)
325
+ end
326
+
327
+ it "logs capture events" do
328
+ payment.capture!(capture_amount)
329
+ expect(payment.capture_events.count).to eq(1)
330
+ expect(payment.capture_events.first.amount).to eq(capture_amount / 100)
331
+ end
332
+ end
333
+ end
334
+
335
+ context "if unsuccessful" do
336
+ it "should not make payment complete" do
337
+ allow(gateway).to receive_messages :capture => failed_response
338
+ expect(payment).to receive(:failure)
339
+ expect(payment).not_to receive(:complete)
340
+ expect { payment.capture! }.to raise_error(Spree::Core::GatewayError)
341
+ end
342
+ end
343
+ end
344
+
345
+ # Regression test for #2119
346
+ context "when payment is completed" do
347
+ before do
348
+ payment.state = 'completed'
349
+ end
350
+
351
+ it "should do nothing" do
352
+ expect(payment).not_to receive(:complete)
353
+ expect(payment.payment_method).not_to receive(:capture)
354
+ expect(payment.log_entries).not_to receive(:create!)
355
+ payment.capture!
356
+ end
357
+ end
358
+ end
359
+
360
+ describe "#void_transaction!" do
361
+ before do
362
+ payment.response_code = '123'
363
+ payment.state = 'pending'
364
+ end
365
+
366
+ context "when profiles are supported" do
367
+ it "should call payment_gateway.void with the payment's response_code" do
368
+ allow(gateway).to receive_messages :payment_profiles_supported? => true
369
+ expect(gateway).to receive(:void).with('123', card, anything).and_return(success_response)
370
+ payment.void_transaction!
371
+ end
372
+ end
373
+
374
+ context "when profiles are not supported" do
375
+ it "should call payment_gateway.void with the payment's response_code" do
376
+ allow(gateway).to receive_messages :payment_profiles_supported? => false
377
+ expect(gateway).to receive(:void).with('123', anything).and_return(success_response)
378
+ payment.void_transaction!
379
+ end
380
+ end
381
+
382
+ it "should log the response" do
383
+ expect(payment.log_entries).to receive(:create!).with(:details => anything)
384
+ payment.void_transaction!
385
+ end
386
+
387
+ context "if successful" do
388
+ it "should update the response_code with the authorization from the gateway" do
389
+ # Change it to something different
390
+ payment.response_code = 'abc'
391
+ payment.void_transaction!
392
+ expect(payment.response_code).to eq('12345')
393
+ end
394
+ end
395
+
396
+ context "if unsuccessful" do
397
+ it "should not void the payment" do
398
+ allow(gateway).to receive_messages :void => failed_response
399
+ expect(payment).not_to receive(:void)
400
+ expect { payment.void_transaction! }.to raise_error(Spree::Core::GatewayError)
401
+ end
402
+ end
403
+
404
+ # Regression test for #2119
405
+ context "if payment is already voided" do
406
+ before do
407
+ payment.state = 'void'
408
+ end
409
+
410
+ it "should not void the payment" do
411
+ expect(payment.payment_method).not_to receive(:void)
412
+ payment.void_transaction!
413
+ end
414
+ end
415
+ end
416
+
417
+ end
418
+
419
+ context "when already processing" do
420
+ it "should return nil without trying to process the source" do
421
+ payment.state = 'processing'
422
+
423
+ expect(payment.process!).to be_nil
424
+ end
425
+ end
426
+
427
+ context "with source required" do
428
+ context "raises an error if no source is specified" do
429
+ before do
430
+ payment.source = nil
431
+ end
432
+
433
+ specify do
434
+ expect { payment.process! }.to raise_error(Spree::Core::GatewayError, Spree.t(:payment_processing_failed))
435
+ end
436
+ end
437
+ end
438
+
439
+ context "with source optional" do
440
+ context "raises no error if source is not specified" do
441
+ before do
442
+ payment.source = nil
443
+ allow(payment.payment_method).to receive_messages(:source_required? => false)
444
+ end
445
+
446
+ specify do
447
+ expect { payment.process! }.not_to raise_error
448
+ end
449
+ end
450
+ end
451
+
452
+ describe "#credit_allowed" do
453
+ # Regression test for #4403 & #4407
454
+ it "is the difference between offsets total and payment amount" do
455
+ payment.amount = 100
456
+ allow(payment).to receive(:offsets_total).and_return(0)
457
+ expect(payment.credit_allowed).to eq(100)
458
+ allow(payment).to receive(:offsets_total).and_return(-80)
459
+ expect(payment.credit_allowed).to eq(20)
460
+ end
461
+ end
462
+
463
+ describe "#can_credit?" do
464
+ it "is true if credit_allowed > 0" do
465
+ allow(payment).to receive(:credit_allowed).and_return(100)
466
+ expect(payment.can_credit?).to be true
467
+ end
468
+
469
+ it "is false if credit_allowed is 0" do
470
+ allow(payment).to receive(:credit_allowed).and_return(0)
471
+ expect(payment.can_credit?).to be false
472
+ end
473
+ end
474
+
475
+ describe "#save" do
476
+ context "captured payments" do
477
+ it "update order payment total" do
478
+ payment = create(:payment, order: order, state: 'completed')
479
+ expect(order.payment_total).to eq payment.amount
480
+ end
481
+ end
482
+
483
+ context "not completed payments" do
484
+ it "doesn't update order payment total" do
485
+ expect {
486
+ Spree::Payment.create(:amount => 100, :order => order)
487
+ }.not_to change { order.payment_total }
488
+ end
489
+
490
+ it "requires a payment method" do
491
+ expect(Spree::Payment.create(amount: 100, order: order)).to have(1).error_on(:payment_method)
492
+ end
493
+ end
494
+
495
+ context 'when the payment was completed but now void' do
496
+ let(:payment) do
497
+ Spree::Payment.create(
498
+ amount: 100,
499
+ order: order,
500
+ state: 'completed'
501
+ )
502
+ end
503
+
504
+ it 'updates order payment total' do
505
+ payment.void
506
+ expect(order.payment_total).to eq 0
507
+ end
508
+ end
509
+
510
+ context "completed orders" do
511
+ before { allow(order).to receive_messages completed?: true }
512
+
513
+ it "updates payment_state and shipments" do
514
+ expect(order.updater).to receive(:update_payment_state)
515
+ expect(order.updater).to receive(:update_shipment_state)
516
+ Spree::Payment.create(amount: 100, order: order, payment_method: gateway)
517
+ end
518
+ end
519
+
520
+ context "when profiles are supported" do
521
+ before do
522
+ allow(gateway).to receive_messages :payment_profiles_supported? => true
523
+ allow(payment.source).to receive_messages :has_payment_profile? => false
524
+ end
525
+
526
+ context "when there is an error connecting to the gateway" do
527
+ it "should call gateway_error " do
528
+ message = double("gateway_error")
529
+ connection_error = ActiveMerchant::ConnectionError.new(message, nil)
530
+ expect(gateway).to receive(:create_profile).and_raise(connection_error)
531
+ expect do
532
+ Spree::Payment.create(
533
+ :amount => 100,
534
+ :order => order,
535
+ :source => card,
536
+ :payment_method => gateway
537
+ )
538
+ end.to raise_error(Spree::Core::GatewayError)
539
+ end
540
+ end
541
+
542
+ context "with multiple payment attempts" do
543
+ let(:attributes) { attributes_for(:credit_card) }
544
+ it "should not try to create profiles on old failed payment attempts" do
545
+ allow_any_instance_of(Spree::Payment).to receive(:payment_method) { gateway }
546
+
547
+ order.payments.create!(
548
+ source_attributes: attributes,
549
+ payment_method: gateway,
550
+ amount: 100
551
+ )
552
+ expect(gateway).to receive(:create_profile).exactly :once
553
+ expect(order.payments.count).to eq(1)
554
+ order.payments.create!(
555
+ source_attributes: attributes,
556
+ payment_method: gateway,
557
+ amount: 100
558
+ )
559
+ end
560
+
561
+ end
562
+
563
+ context "when successfully connecting to the gateway" do
564
+ it "should create a payment profile" do
565
+ expect(payment.payment_method).to receive :create_profile
566
+ payment = Spree::Payment.create(
567
+ :amount => 100,
568
+ :order => order,
569
+ :source => card,
570
+ :payment_method => gateway
571
+ )
572
+ end
573
+ end
574
+ end
575
+
576
+ context "when profiles are not supported" do
577
+ before { allow(gateway).to receive_messages :payment_profiles_supported? => false }
578
+
579
+ it "should not create a payment profile" do
580
+ expect(gateway).not_to receive :create_profile
581
+ payment = Spree::Payment.create(
582
+ :amount => 100,
583
+ :order => order,
584
+ :source => card,
585
+ :payment_method => gateway
586
+ )
587
+ end
588
+ end
589
+ end
590
+
591
+ describe "#build_source" do
592
+ let(:params) do
593
+ {
594
+ :amount => 100,
595
+ :payment_method => gateway,
596
+ :source_attributes => {
597
+ :expiry =>"01 / 99",
598
+ :number => '1234567890123',
599
+ :verification_value => '123',
600
+ :name => 'Spree Commerce'
601
+ }
602
+ }
603
+ end
604
+
605
+ it "should build the payment's source" do
606
+ payment = Spree::Payment.new(params)
607
+ expect(payment).to be_valid
608
+ expect(payment.source).not_to be_nil
609
+ end
610
+
611
+ it "assigns user and gateway to payment source" do
612
+ order = create(:order)
613
+ source = order.payments.new(params).source
614
+
615
+ expect(source.user_id).to eq order.user_id
616
+ expect(source.payment_method_id).to eq gateway.id
617
+ end
618
+
619
+ it "errors when payment source not valid" do
620
+ params = { :amount => 100, :payment_method => gateway,
621
+ :source_attributes => {:expiry => "1 / 12" }}
622
+
623
+ payment = Spree::Payment.new(params)
624
+ expect(payment).not_to be_valid
625
+ expect(payment.source).not_to be_nil
626
+ expect(payment.source.error_on(:number).size).to eq(1)
627
+ expect(payment.source.error_on(:verification_value).size).to eq(1)
628
+ end
629
+
630
+ it "does not build a new source when duplicating the model with source_attributes set" do
631
+ payment = create(:payment)
632
+ payment.source_attributes = params[:source_attributes]
633
+ expect { payment.dup }.to_not change { payment.source }
634
+ end
635
+ end
636
+
637
+ describe "#currency" do
638
+ before { allow(order).to receive(:currency) { "ABC" } }
639
+ it "returns the order currency" do
640
+ expect(payment.currency).to eq("ABC")
641
+ end
642
+ end
643
+
644
+ describe "#display_amount" do
645
+ it "returns a Spree::Money for this amount" do
646
+ expect(payment.display_amount).to eq(Spree::Money.new(payment.amount))
647
+ end
648
+ end
649
+
650
+ # Regression test for #2216
651
+ describe "#gateway_options" do
652
+ before { allow(order).to receive_messages(:last_ip_address => "192.168.1.1") }
653
+
654
+ it "contains an IP" do
655
+ expect(payment.gateway_options[:ip]).to eq(order.last_ip_address)
656
+ end
657
+
658
+ it "contains the email address from a persisted order" do
659
+ # Sets the payment's order to a different Ruby object entirely
660
+ payment.order = Spree::Order.find(payment.order_id)
661
+ email = 'foo@example.com'
662
+ order.update_attributes(:email => email)
663
+ expect(payment.gateway_options[:email]).to eq(email)
664
+ end
665
+ end
666
+
667
+ describe "#set_unique_number" do
668
+ # Regression test for #1998
669
+ it "sets a unique number on create" do
670
+ payment.generate_number
671
+ payment.save
672
+
673
+ expect(payment.number).to_not be_blank
674
+ expect(payment.number.length).to eq 8
675
+ expect(payment.number).to be_a(String)
676
+ end
677
+
678
+ # Regression test for #3733
679
+ it "does not regenerate the number on re-save" do
680
+ payment.run_callbacks(:create)
681
+ payment.save
682
+ old_number = payment.number
683
+ payment.save
684
+ expect(payment.number).to eq old_number
685
+ end
686
+
687
+ context "other payment exists" do
688
+ let(:other_payment) {
689
+ payment = Spree::Payment.new
690
+ payment.source = card
691
+ payment.order = order
692
+ payment.payment_method = gateway
693
+ payment
694
+ }
695
+
696
+ it "doesn't set duplicate number" do
697
+ other_payment.run_callbacks(:create)
698
+ other_payment.save!
699
+
700
+ payment.run_callbacks(:create)
701
+ payment.save!
702
+
703
+ expect(payment.number).to_not be_blank
704
+ expect(payment.number).to_not eq other_payment.number
705
+ end
706
+ end
707
+ end
708
+
709
+ describe "#amount=" do
710
+ before do
711
+ subject.amount = amount
712
+ end
713
+
714
+ context "when the amount is a string" do
715
+ context "amount is a decimal" do
716
+ let(:amount) { '2.99' }
717
+
718
+ it '#amount' do
719
+ expect(subject.amount).to eql(BigDecimal('2.99'))
720
+ end
721
+ end
722
+
723
+ context "amount is an integer" do
724
+ let(:amount) { '2' }
725
+
726
+ it '#amount' do
727
+ expect(subject.amount).to eql(BigDecimal('2.0'))
728
+ end
729
+ end
730
+
731
+ context "amount contains a dollar sign" do
732
+ let(:amount) { '$2.99' }
733
+
734
+ it '#amount' do
735
+ expect(subject.amount).to eql(BigDecimal('2.99'))
736
+ end
737
+ end
738
+
739
+ context "amount contains a comma" do
740
+ let(:amount) { '$2,999.99' }
741
+
742
+ it '#amount' do
743
+ expect(subject.amount).to eql(BigDecimal('2999.99'))
744
+ end
745
+ end
746
+
747
+ context "amount contains a negative sign" do
748
+ let(:amount) { '-2.99' }
749
+
750
+ it '#amount' do
751
+ expect(subject.amount).to eql(BigDecimal('-2.99'))
752
+ end
753
+ end
754
+
755
+ context "amount is invalid" do
756
+ let(:amount) { 'invalid' }
757
+
758
+ # this is a strange default for ActiveRecord
759
+
760
+ it '#amount' do
761
+ expect(subject.amount).to eql(BigDecimal('0'))
762
+ end
763
+ end
764
+
765
+ context "amount is an empty string" do
766
+ let(:amount) { '' }
767
+
768
+ it '#amount' do
769
+ expect(subject.amount).to be_nil
770
+ end
771
+ end
772
+ end
773
+
774
+ context "when the amount is a number" do
775
+ let(:amount) { 1.55 }
776
+
777
+ it '#amount' do
778
+ expect(subject.amount).to eql(BigDecimal('1.55'))
779
+ end
780
+ end
781
+
782
+ context "when the locale uses a coma as a decimal separator" do
783
+ before(:each) do
784
+ I18n.backend.store_translations(:fr, { :number => { :currency => { :format => { :delimiter => ' ', :separator => ',' } } } })
785
+ I18n.locale = :fr
786
+ subject.amount = amount
787
+ end
788
+
789
+ after do
790
+ I18n.locale = I18n.default_locale
791
+ end
792
+
793
+ context "amount is a decimal" do
794
+ let(:amount) { '2,99' }
795
+
796
+ it '#amount' do
797
+ expect(subject.amount).to eql(BigDecimal('2.99'))
798
+ end
799
+ end
800
+
801
+ context "amount contains a $ sign" do
802
+ let(:amount) { '2,99 $' }
803
+
804
+ it '#amount' do
805
+ expect(subject.amount).to eql(BigDecimal('2.99'))
806
+ end
807
+ end
808
+
809
+ context "amount is a number" do
810
+ let(:amount) { 2.99 }
811
+
812
+ it '#amount' do
813
+ expect(subject.amount).to eql(BigDecimal('2.99'))
814
+ end
815
+ end
816
+
817
+ context "amount contains a negative sign" do
818
+ let(:amount) { '-2,99 $' }
819
+
820
+ it '#amount' do
821
+ expect(subject.amount).to eql(BigDecimal('-2.99'))
822
+ end
823
+ end
824
+
825
+ context "amount uses a dot as a decimal separator" do
826
+ let(:amount) { '2.99' }
827
+
828
+ it '#amount' do
829
+ expect(subject.amount).to eql(BigDecimal('2.99'))
830
+ end
831
+ end
832
+ end
833
+ end
834
+
835
+ describe "is_avs_risky?" do
836
+ it "returns false if avs_response included in NON_RISKY_AVS_CODES" do
837
+ ('A'..'Z').reject{ |x| subject.class::RISKY_AVS_CODES.include?(x) }.to_a.each do |char|
838
+ payment.update_attribute(:avs_response, char)
839
+ expect(payment.is_avs_risky?).to eq false
840
+ end
841
+ end
842
+
843
+ it "returns false if avs_response.blank?" do
844
+ payment.update_attribute(:avs_response, nil)
845
+ expect(payment.is_avs_risky?).to eq false
846
+ payment.update_attribute(:avs_response, '')
847
+ expect(payment.is_avs_risky?).to eq false
848
+ end
849
+
850
+ it "returns true if avs_response in RISKY_AVS_CODES" do
851
+ # should use avs_response_code helper
852
+ ('A'..'Z').reject{ |x| subject.class::NON_RISKY_AVS_CODES.include?(x) }.to_a.each do |char|
853
+ payment.update_attribute(:avs_response, char)
854
+ expect(payment.is_avs_risky?).to eq true
855
+ end
856
+ end
857
+ end
858
+
859
+ describe "is_cvv_risky?" do
860
+ it "returns false if cvv_response_code == 'M'" do
861
+ payment.update_attribute(:cvv_response_code, "M")
862
+ expect(payment.is_cvv_risky?).to eq(false)
863
+ end
864
+
865
+ it "returns false if cvv_response_code == nil" do
866
+ payment.update_attribute(:cvv_response_code, nil)
867
+ expect(payment.is_cvv_risky?).to eq(false)
868
+ end
869
+
870
+ it "returns false if cvv_response_message == ''" do
871
+ payment.update_attribute(:cvv_response_message, '')
872
+ expect(payment.is_cvv_risky?).to eq(false)
873
+ end
874
+
875
+ it "returns true if cvv_response_code == [A-Z], omitting D" do
876
+ # should use cvv_response_code helper
877
+ (%w{N P S U} << "").each do |char|
878
+ payment.update_attribute(:cvv_response_code, char)
879
+ expect(payment.is_cvv_risky?).to eq(true)
880
+ end
881
+ end
882
+ end
883
+
884
+ describe "#editable?" do
885
+ subject { payment }
886
+
887
+ before do
888
+ subject.state = state
889
+ end
890
+
891
+ context "when the state is 'checkout'" do
892
+ let(:state) { 'checkout' }
893
+
894
+ its(:editable?) { should be(true) }
895
+ end
896
+
897
+ context "when the state is 'pending'" do
898
+ let(:state) { 'pending' }
899
+
900
+ its(:editable?) { should be(true) }
901
+ end
902
+
903
+ %w[processing completed failed void invalid].each do |state|
904
+ context "when the state is '#{state}'" do
905
+ let(:state) { state }
906
+
907
+ its(:editable?) { should be(false) }
908
+ end
909
+ end
910
+ end
911
+
912
+ # Regression test for #4072 (kinda)
913
+ # The need for this was discovered in the research for #4072
914
+ context "state changes" do
915
+ it "are logged to the database" do
916
+ expect(payment.state_changes).to be_empty
917
+ expect(payment.process!).to be true
918
+ expect(payment.state_changes.count).to eq(2)
919
+ changes = payment.state_changes.map { |change| { change.previous_state => change.next_state} }
920
+ expect(changes).to match_array([
921
+ {"checkout" => "processing"},
922
+ { "processing" => "pending"}
923
+ ])
924
+ end
925
+ end
926
+ end