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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/Gemfile +3 -0
- data/Rakefile +30 -0
- data/app/assets/javascripts/spree.js.coffee.erb +1 -1
- data/app/models/spree/ability.rb +1 -1
- data/app/models/spree/base.rb +3 -1
- data/app/models/spree/order_updater.rb +2 -1
- data/app/models/spree/price.rb +7 -12
- data/app/models/spree/product.rb +3 -2
- data/app/models/spree/reimbursement.rb +1 -1
- data/app/models/spree/state.rb +2 -0
- data/app/models/spree/zone.rb +1 -1
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/testing_support/shoulda_matcher_configuration.rb +6 -0
- data/script/rails +9 -0
- data/spec/fixtures/thinking-cat.jpg +0 -0
- data/spec/helpers/base_helper_spec.rb +137 -0
- data/spec/helpers/products_helper_spec.rb +224 -0
- data/spec/lib/calculated_adjustments_spec.rb +7 -0
- data/spec/lib/i18n_spec.rb +123 -0
- data/spec/lib/search/base_spec.rb +86 -0
- data/spec/lib/spree/core/controller_helpers/auth_spec.rb +101 -0
- data/spec/lib/spree/core/controller_helpers/order_spec.rb +95 -0
- data/spec/lib/spree/core/controller_helpers/search_spec.rb +17 -0
- data/spec/lib/spree/core/controller_helpers/store_spec.rb +16 -0
- data/spec/lib/spree/core/controller_helpers/strong_parameters_spec.rb +39 -0
- data/spec/lib/spree/core/delegate_belongs_to_spec.rb +22 -0
- data/spec/lib/spree/core/importer/order_spec.rb +502 -0
- data/spec/lib/spree/core/validators/email_spec.rb +53 -0
- data/spec/lib/spree/localized_number_spec.rb +38 -0
- data/spec/lib/spree/migrations_spec.rb +34 -0
- data/spec/lib/spree/money_spec.rb +122 -0
- data/spec/lib/tasks/exchanges_spec.rb +136 -0
- data/spec/mailers/order_mailer_spec.rb +124 -0
- data/spec/mailers/reimbursement_mailer_spec.rb +47 -0
- data/spec/mailers/shipment_mailer_spec.rb +63 -0
- data/spec/mailers/test_mailer_spec.rb +24 -0
- data/spec/models/spree/ability_spec.rb +246 -0
- data/spec/models/spree/address_spec.rb +291 -0
- data/spec/models/spree/adjustable/adjustments_updater_spec.rb +286 -0
- data/spec/models/spree/adjustment_spec.rb +163 -0
- data/spec/models/spree/app_configuration_spec.rb +23 -0
- data/spec/models/spree/asset_spec.rb +25 -0
- data/spec/models/spree/calculator/default_tax_spec.rb +127 -0
- data/spec/models/spree/calculator/flat_percent_item_total_spec.rb +25 -0
- data/spec/models/spree/calculator/flat_rate_spec.rb +47 -0
- data/spec/models/spree/calculator/flexi_rate_spec.rb +41 -0
- data/spec/models/spree/calculator/percent_on_line_item_spec.rb +15 -0
- data/spec/models/spree/calculator/price_sack_spec.rb +30 -0
- data/spec/models/spree/calculator/refunds/default_refund_amount_spec.rb +51 -0
- data/spec/models/spree/calculator/shipping.rb +8 -0
- data/spec/models/spree/calculator/shipping/flat_percent_item_total_spec.rb +23 -0
- data/spec/models/spree/calculator/shipping/flat_rate_spec.rb +13 -0
- data/spec/models/spree/calculator/shipping/flexi_rate_spec.rb +52 -0
- data/spec/models/spree/calculator/shipping/per_item_spec.rb +20 -0
- data/spec/models/spree/calculator/shipping/price_sack_spec.rb +29 -0
- data/spec/models/spree/calculator/tiered_flat_rate_spec.rb +40 -0
- data/spec/models/spree/calculator/tiered_percent_spec.rb +51 -0
- data/spec/models/spree/calculator_spec.rb +69 -0
- data/spec/models/spree/classification_spec.rb +93 -0
- data/spec/models/spree/concerns/display_money_spec.rb +43 -0
- data/spec/models/spree/country_spec.rb +18 -0
- data/spec/models/spree/credit_card_spec.rb +324 -0
- data/spec/models/spree/customer_return_spec.rb +262 -0
- data/spec/models/spree/exchange_spec.rb +75 -0
- data/spec/models/spree/gateway/bogus_simple.rb +20 -0
- data/spec/models/spree/gateway/bogus_spec.rb +13 -0
- data/spec/models/spree/gateway_spec.rb +54 -0
- data/spec/models/spree/image_spec.rb +5 -0
- data/spec/models/spree/inventory_unit_spec.rb +242 -0
- data/spec/models/spree/line_item_spec.rb +267 -0
- data/spec/models/spree/option_type_spec.rb +14 -0
- data/spec/models/spree/option_value_spec.rb +13 -0
- data/spec/models/spree/order/address_spec.rb +50 -0
- data/spec/models/spree/order/adjustments_spec.rb +29 -0
- data/spec/models/spree/order/callbacks_spec.rb +42 -0
- data/spec/models/spree/order/checkout_spec.rb +764 -0
- data/spec/models/spree/order/currency_updater_spec.rb +32 -0
- data/spec/models/spree/order/finalizing_spec.rb +117 -0
- data/spec/models/spree/order/helpers_spec.rb +5 -0
- data/spec/models/spree/order/payment_spec.rb +214 -0
- data/spec/models/spree/order/risk_assessment_spec.rb +84 -0
- data/spec/models/spree/order/shipments_spec.rb +43 -0
- data/spec/models/spree/order/state_machine_spec.rb +216 -0
- data/spec/models/spree/order/tax_spec.rb +84 -0
- data/spec/models/spree/order/totals_spec.rb +24 -0
- data/spec/models/spree/order/updating_spec.rb +18 -0
- data/spec/models/spree/order/validations_spec.rb +15 -0
- data/spec/models/spree/order_contents_spec.rb +256 -0
- data/spec/models/spree/order_inventory_spec.rb +228 -0
- data/spec/models/spree/order_merger_spec.rb +133 -0
- data/spec/models/spree/order_spec.rb +954 -0
- data/spec/models/spree/order_updater_spec.rb +283 -0
- data/spec/models/spree/payment/gateway_options_spec.rb +119 -0
- data/spec/models/spree/payment_method_spec.rb +95 -0
- data/spec/models/spree/payment_spec.rb +926 -0
- data/spec/models/spree/preference_spec.rb +80 -0
- data/spec/models/spree/preferences/configuration_spec.rb +30 -0
- data/spec/models/spree/preferences/preferable_spec.rb +348 -0
- data/spec/models/spree/preferences/scoped_store_spec.rb +58 -0
- data/spec/models/spree/preferences/store_spec.rb +46 -0
- data/spec/models/spree/price_spec.rb +42 -0
- data/spec/models/spree/product/scopes_spec.rb +148 -0
- data/spec/models/spree/product_duplicator_spec.rb +103 -0
- data/spec/models/spree/product_filter_spec.rb +26 -0
- data/spec/models/spree/product_option_type_spec.rb +5 -0
- data/spec/models/spree/product_property_spec.rb +11 -0
- data/spec/models/spree/product_spec.rb +474 -0
- data/spec/models/spree/promotion/actions/create_adjustment_spec.rb +50 -0
- data/spec/models/spree/promotion/actions/create_item_adjustments_spec.rb +148 -0
- data/spec/models/spree/promotion/actions/create_line_items_spec.rb +86 -0
- data/spec/models/spree/promotion/actions/free_shipping_spec.rb +36 -0
- data/spec/models/spree/promotion/rules/first_order_spec.rb +75 -0
- data/spec/models/spree/promotion/rules/item_total_spec.rb +282 -0
- data/spec/models/spree/promotion/rules/one_use_per_user_spec.rb +42 -0
- data/spec/models/spree/promotion/rules/option_value_spec.rb +90 -0
- data/spec/models/spree/promotion/rules/product_spec.rb +143 -0
- data/spec/models/spree/promotion/rules/taxon_spec.rb +102 -0
- data/spec/models/spree/promotion/rules/user_logged_in_spec.rb +27 -0
- data/spec/models/spree/promotion/rules/user_spec.rb +37 -0
- data/spec/models/spree/promotion_action_spec.rb +10 -0
- data/spec/models/spree/promotion_category_spec.rb +17 -0
- data/spec/models/spree/promotion_handler/cart_spec.rb +102 -0
- data/spec/models/spree/promotion_handler/coupon_spec.rb +323 -0
- data/spec/models/spree/promotion_handler/free_shipping_spec.rb +48 -0
- data/spec/models/spree/promotion_handler/page_spec.rb +44 -0
- data/spec/models/spree/promotion_rule_spec.rb +29 -0
- data/spec/models/spree/promotion_spec.rb +603 -0
- data/spec/models/spree/property_spec.rb +5 -0
- data/spec/models/spree/prototype_spec.rb +5 -0
- data/spec/models/spree/refund_spec.rb +195 -0
- data/spec/models/spree/reimbursement/credit_spec.rb +36 -0
- data/spec/models/spree/reimbursement/reimbursement_type_engine_spec.rb +140 -0
- data/spec/models/spree/reimbursement/reimbursement_type_validator_spec.rb +83 -0
- data/spec/models/spree/reimbursement_performer_spec.rb +30 -0
- data/spec/models/spree/reimbursement_spec.rb +215 -0
- data/spec/models/spree/reimbursement_tax_calculator_spec.rb +51 -0
- data/spec/models/spree/reimbursement_type/credit_spec.rb +53 -0
- data/spec/models/spree/reimbursement_type/exchange_spec.rb +46 -0
- data/spec/models/spree/reimbursement_type/original_payment_spec.rb +55 -0
- data/spec/models/spree/return_authorization_spec.rb +250 -0
- data/spec/models/spree/return_item/eligibility_validator/default_spec.rb +77 -0
- data/spec/models/spree/return_item/eligibility_validator/inventory_shipped_spec.rb +58 -0
- data/spec/models/spree/return_item/eligibility_validator/no_reimbursements_spec.rb +61 -0
- data/spec/models/spree/return_item/eligibility_validator/order_completed_spec.rb +32 -0
- data/spec/models/spree/return_item/eligibility_validator/rma_required_spec.rb +29 -0
- data/spec/models/spree/return_item/eligibility_validator/time_since_purchase_spec.rb +35 -0
- data/spec/models/spree/return_item/exchange_variant_eligibility/same_option_value_spec.rb +65 -0
- data/spec/models/spree/return_item/exchange_variant_eligibility/same_product_spec.rb +43 -0
- data/spec/models/spree/return_item_spec.rb +682 -0
- data/spec/models/spree/returns_calculator_spec.rb +14 -0
- data/spec/models/spree/shipment_spec.rb +740 -0
- data/spec/models/spree/shipping_calculator_spec.rb +45 -0
- data/spec/models/spree/shipping_category_spec.rb +5 -0
- data/spec/models/spree/shipping_method_spec.rb +88 -0
- data/spec/models/spree/shipping_rate_spec.rb +141 -0
- data/spec/models/spree/state_spec.rb +18 -0
- data/spec/models/spree/stock/availability_validator_spec.rb +36 -0
- data/spec/models/spree/stock/content_item_spec.rb +22 -0
- data/spec/models/spree/stock/coordinator_spec.rb +51 -0
- data/spec/models/spree/stock/differentiator_spec.rb +39 -0
- data/spec/models/spree/stock/estimator_spec.rb +154 -0
- data/spec/models/spree/stock/inventory_unit_builder_spec.rb +38 -0
- data/spec/models/spree/stock/package_spec.rb +194 -0
- data/spec/models/spree/stock/packer_spec.rb +70 -0
- data/spec/models/spree/stock/prioritizer_spec.rb +125 -0
- data/spec/models/spree/stock/quantifier_spec.rb +97 -0
- data/spec/models/spree/stock/splitter/backordered_spec.rb +29 -0
- data/spec/models/spree/stock/splitter/base_spec.rb +21 -0
- data/spec/models/spree/stock/splitter/shipping_category_spec.rb +47 -0
- data/spec/models/spree/stock/splitter/weight_spec.rb +32 -0
- data/spec/models/spree/stock_item_spec.rb +410 -0
- data/spec/models/spree/stock_location_spec.rb +243 -0
- data/spec/models/spree/stock_movement_spec.rb +56 -0
- data/spec/models/spree/stock_transfer_spec.rb +50 -0
- data/spec/models/spree/store_spec.rb +50 -0
- data/spec/models/spree/tax_category_spec.rb +27 -0
- data/spec/models/spree/tax_rate_spec.rb +382 -0
- data/spec/models/spree/taxon_spec.rb +74 -0
- data/spec/models/spree/taxonomy_spec.rb +18 -0
- data/spec/models/spree/tracker_spec.rb +21 -0
- data/spec/models/spree/user_spec.rb +130 -0
- data/spec/models/spree/validations/db_maximum_length_validator_spec.rb +24 -0
- data/spec/models/spree/variant_spec.rb +523 -0
- data/spec/models/spree/zone_spec.rb +444 -0
- data/spec/spec_helper.rb +74 -0
- data/spec/support/big_decimal.rb +5 -0
- data/spec/support/concerns/adjustment_source_spec.rb +23 -0
- data/spec/support/concerns/default_price_spec.rb +28 -0
- data/spec/support/rake.rb +13 -0
- data/spec/support/test_gateway.rb +2 -0
- data/spree_core.gemspec +48 -0
- 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
|