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,267 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Spree::LineItem, :type => :model do
|
|
4
|
+
let(:order) { create :order_with_line_items, line_items_count: 1 }
|
|
5
|
+
let(:line_item) { order.line_items.first }
|
|
6
|
+
|
|
7
|
+
before { create(:store) }
|
|
8
|
+
|
|
9
|
+
context '#save' do
|
|
10
|
+
it 'touches the order' do
|
|
11
|
+
expect(line_item.order).to receive(:touch)
|
|
12
|
+
line_item.touch
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
context '#destroy' do
|
|
17
|
+
it "fetches deleted products" do
|
|
18
|
+
line_item.product.destroy
|
|
19
|
+
expect(line_item.reload.product).to be_a Spree::Product
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "fetches deleted variants" do
|
|
23
|
+
line_item.variant.destroy
|
|
24
|
+
expect(line_item.reload.variant).to be_a Spree::Variant
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "returns inventory when a line item is destroyed" do
|
|
28
|
+
expect_any_instance_of(Spree::OrderInventory).to receive(:verify)
|
|
29
|
+
line_item.destroy
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "deletes inventory units" do
|
|
33
|
+
expect { line_item.destroy }.to change { line_item.inventory_units.count }.from(1).to(0)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
context "#save" do
|
|
38
|
+
context "line item changes" do
|
|
39
|
+
before do
|
|
40
|
+
line_item.quantity = line_item.quantity + 1
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "triggers adjustment total recalculation" do
|
|
44
|
+
expect(line_item).to receive(:update_tax_charge) # Regression test for https://github.com/spree/spree/issues/4671
|
|
45
|
+
expect(line_item).to receive(:recalculate_adjustments)
|
|
46
|
+
line_item.save
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
context "line item does not change" do
|
|
51
|
+
it "does not trigger adjustment total recalculation" do
|
|
52
|
+
expect(line_item).not_to receive(:recalculate_adjustments)
|
|
53
|
+
line_item.save
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
context "target_shipment is provided" do
|
|
58
|
+
it "verifies inventory" do
|
|
59
|
+
line_item.target_shipment = Spree::Shipment.new
|
|
60
|
+
expect_any_instance_of(Spree::OrderInventory).to receive(:verify)
|
|
61
|
+
line_item.save
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
context "#create" do
|
|
67
|
+
let(:variant) { create(:variant) }
|
|
68
|
+
|
|
69
|
+
before do
|
|
70
|
+
create(:tax_rate, :zone => order.tax_zone, :tax_category => variant.tax_category)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
context "when order has a tax zone" do
|
|
74
|
+
before do
|
|
75
|
+
expect(order.tax_zone).to be_present
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it "creates a tax adjustment" do
|
|
79
|
+
order.contents.add(variant)
|
|
80
|
+
line_item = order.find_line_item_by_variant(variant)
|
|
81
|
+
expect(line_item.adjustments.tax.count).to eq(1)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
context "when order does not have a tax zone" do
|
|
86
|
+
before do
|
|
87
|
+
order.bill_address = nil
|
|
88
|
+
order.ship_address = nil
|
|
89
|
+
order.save
|
|
90
|
+
expect(order.reload.tax_zone).to be_nil
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "does not create a tax adjustment" do
|
|
94
|
+
order.contents.add(variant)
|
|
95
|
+
line_item = order.find_line_item_by_variant(variant)
|
|
96
|
+
expect(line_item.adjustments.tax.count).to eq(0)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Test for #3391
|
|
102
|
+
context '#copy_price' do
|
|
103
|
+
it "copies over a variant's prices" do
|
|
104
|
+
line_item.price = nil
|
|
105
|
+
line_item.cost_price = nil
|
|
106
|
+
line_item.currency = nil
|
|
107
|
+
line_item.copy_price
|
|
108
|
+
variant = line_item.variant
|
|
109
|
+
expect(line_item.price).to eq(variant.price)
|
|
110
|
+
expect(line_item.cost_price).to eq(variant.cost_price)
|
|
111
|
+
expect(line_item.currency).to eq(variant.currency)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Test for #3481
|
|
116
|
+
context '#copy_tax_category' do
|
|
117
|
+
it "copies over a variant's tax category" do
|
|
118
|
+
line_item.tax_category = nil
|
|
119
|
+
line_item.copy_tax_category
|
|
120
|
+
expect(line_item.tax_category).to eq(line_item.variant.tax_category)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
describe '.discounted_amount' do
|
|
125
|
+
it "returns the amount minus any discounts" do
|
|
126
|
+
line_item.price = 10
|
|
127
|
+
line_item.quantity = 2
|
|
128
|
+
line_item.promo_total = -5
|
|
129
|
+
expect(line_item.discounted_amount).to eq(15)
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
describe "#discounted_money" do
|
|
134
|
+
it "should return a money object with the discounted amount" do
|
|
135
|
+
expect(line_item.discounted_money.to_s).to eq "$10.00"
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
describe '.currency' do
|
|
140
|
+
it 'returns the globally configured currency' do
|
|
141
|
+
line_item.currency == 'USD'
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
describe ".money" do
|
|
146
|
+
before do
|
|
147
|
+
line_item.price = 3.50
|
|
148
|
+
line_item.quantity = 2
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
it "returns a Spree::Money representing the total for this line item" do
|
|
152
|
+
expect(line_item.money.to_s).to eq("$7.00")
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
describe '.single_money' do
|
|
157
|
+
before { line_item.price = 3.50 }
|
|
158
|
+
it "returns a Spree::Money representing the price for one variant" do
|
|
159
|
+
expect(line_item.single_money.to_s).to eq("$3.50")
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
context "has inventory (completed order so items were already unstocked)" do
|
|
164
|
+
let(:order) { Spree::Order.create(email: 'spree@example.com') }
|
|
165
|
+
let(:variant) { create(:variant) }
|
|
166
|
+
|
|
167
|
+
context "nothing left on stock" do
|
|
168
|
+
before do
|
|
169
|
+
variant.stock_items.update_all count_on_hand: 5, backorderable: false
|
|
170
|
+
order.contents.add(variant, 5)
|
|
171
|
+
order.create_proposed_shipments
|
|
172
|
+
order.finalize!
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
it "allows to decrease item quantity" do
|
|
176
|
+
line_item = order.line_items.first
|
|
177
|
+
line_item.quantity -= 1
|
|
178
|
+
line_item.target_shipment = order.shipments.first
|
|
179
|
+
|
|
180
|
+
line_item.save
|
|
181
|
+
expect(line_item.errors_on(:quantity).size).to eq(0)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
it "doesnt allow to increase item quantity" do
|
|
185
|
+
line_item = order.line_items.first
|
|
186
|
+
line_item.quantity += 2
|
|
187
|
+
line_item.target_shipment = order.shipments.first
|
|
188
|
+
|
|
189
|
+
line_item.save
|
|
190
|
+
expect(line_item.errors_on(:quantity).size).to eq(1)
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
context "2 items left on stock" do
|
|
195
|
+
before do
|
|
196
|
+
variant.stock_items.update_all count_on_hand: 7, backorderable: false
|
|
197
|
+
order.contents.add(variant, 5)
|
|
198
|
+
order.create_proposed_shipments
|
|
199
|
+
order.finalize!
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
it "allows to increase quantity up to stock availability" do
|
|
203
|
+
line_item = order.line_items.first
|
|
204
|
+
line_item.quantity += 2
|
|
205
|
+
line_item.target_shipment = order.shipments.first
|
|
206
|
+
|
|
207
|
+
line_item.save
|
|
208
|
+
expect(line_item.errors_on(:quantity).size).to eq(0)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
it "doesnt allow to increase quantity over stock availability" do
|
|
212
|
+
line_item = order.line_items.first
|
|
213
|
+
line_item.quantity += 3
|
|
214
|
+
line_item.target_shipment = order.shipments.first
|
|
215
|
+
|
|
216
|
+
line_item.save
|
|
217
|
+
expect(line_item.errors_on(:quantity).size).to eq(1)
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
context "currency same as order.currency" do
|
|
223
|
+
it "is a valid line item" do
|
|
224
|
+
line_item = order.line_items.first
|
|
225
|
+
line_item.currency = order.currency
|
|
226
|
+
line_item.valid?
|
|
227
|
+
|
|
228
|
+
expect(line_item.error_on(:currency).size).to eq(0)
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
context "currency different than order.currency" do
|
|
233
|
+
it "is not a valid line item" do
|
|
234
|
+
line_item = order.line_items.first
|
|
235
|
+
line_item.currency = "no currency"
|
|
236
|
+
line_item.valid?
|
|
237
|
+
|
|
238
|
+
expect(line_item.error_on(:currency).size).to eq(1)
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
describe "#options=" do
|
|
243
|
+
it "can handle updating a blank line item with no order" do
|
|
244
|
+
line_item.options = { price: 123 }
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
it "updates the data provided in the options" do
|
|
248
|
+
line_item.options = { price: 123 }
|
|
249
|
+
expect(line_item.price).to eq 123
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
it "updates the price based on the options provided" do
|
|
253
|
+
expect(line_item).to receive(:gift_wrap=).with(true)
|
|
254
|
+
expect(line_item.variant).to receive(:gift_wrap_price_modifier_amount_in).with("USD", true).and_return 1.99
|
|
255
|
+
line_item.options = { gift_wrap: true }
|
|
256
|
+
expect(line_item.price).to eq 21.98
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
describe "precision of pre_tax_amount" do
|
|
261
|
+
let!(:line_item) { create :line_item, pre_tax_amount: 4.2051 }
|
|
262
|
+
|
|
263
|
+
it "keeps four digits of precision even when reloading" do
|
|
264
|
+
expect(line_item.reload.pre_tax_amount).to eq(4.2051)
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Spree::OptionType, :type => :model do
|
|
4
|
+
context "touching" do
|
|
5
|
+
it "should touch a product" do
|
|
6
|
+
product_option_type = create(:product_option_type)
|
|
7
|
+
option_type = product_option_type.option_type
|
|
8
|
+
product = product_option_type.product
|
|
9
|
+
product.update_column(:updated_at, 1.day.ago)
|
|
10
|
+
option_type.touch
|
|
11
|
+
expect(product.reload.updated_at).to be_within(3.seconds).of(Time.now)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Spree::OptionValue, :type => :model do
|
|
4
|
+
context "touching" do
|
|
5
|
+
it "should touch a variant" do
|
|
6
|
+
variant = create(:variant)
|
|
7
|
+
option_value = variant.option_values.first
|
|
8
|
+
variant.update_column(:updated_at, 1.day.ago)
|
|
9
|
+
option_value.touch
|
|
10
|
+
expect(variant.reload.updated_at).to be_within(3.seconds).of(Time.now)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Spree::Order, :type => :model do
|
|
4
|
+
let(:order) { Spree::Order.new }
|
|
5
|
+
|
|
6
|
+
context 'validation' do
|
|
7
|
+
context "when @use_billing is populated" do
|
|
8
|
+
before do
|
|
9
|
+
order.bill_address = stub_model(Spree::Address)
|
|
10
|
+
order.ship_address = nil
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
context "with true" do
|
|
14
|
+
before { order.use_billing = true }
|
|
15
|
+
|
|
16
|
+
it "clones the bill address to the ship address" do
|
|
17
|
+
order.valid?
|
|
18
|
+
expect(order.ship_address).to eq(order.bill_address)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
context "with 'true'" do
|
|
23
|
+
before { order.use_billing = 'true' }
|
|
24
|
+
|
|
25
|
+
it "clones the bill address to the shipping" do
|
|
26
|
+
order.valid?
|
|
27
|
+
expect(order.ship_address).to eq(order.bill_address)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
context "with '1'" do
|
|
32
|
+
before { order.use_billing = '1' }
|
|
33
|
+
|
|
34
|
+
it "clones the bill address to the shipping" do
|
|
35
|
+
order.valid?
|
|
36
|
+
expect(order.ship_address).to eq(order.bill_address)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
context "with something other than a 'truthful' value" do
|
|
41
|
+
before { order.use_billing = '0' }
|
|
42
|
+
|
|
43
|
+
it "does not clone the bill address to the shipping" do
|
|
44
|
+
order.valid?
|
|
45
|
+
expect(order.ship_address).to be_nil
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Spree::Order do
|
|
4
|
+
context "when an order has an adjustment that zeroes the total, but another adjustment for shipping that raises it above zero" do
|
|
5
|
+
let!(:persisted_order) { create(:order) }
|
|
6
|
+
let!(:line_item) { create(:line_item) }
|
|
7
|
+
let!(:shipping_method) do
|
|
8
|
+
sm = create(:shipping_method)
|
|
9
|
+
sm.calculator.preferred_amount = 10
|
|
10
|
+
sm.save
|
|
11
|
+
sm
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
before do
|
|
15
|
+
# Don't care about available payment methods in this test
|
|
16
|
+
allow(persisted_order).to receive_messages(:has_available_payment => false)
|
|
17
|
+
persisted_order.line_items << line_item
|
|
18
|
+
create(:adjustment, amount: -line_item.amount, label: "Promotion", adjustable: line_item, order: persisted_order)
|
|
19
|
+
persisted_order.state = 'delivery'
|
|
20
|
+
persisted_order.save # To ensure new state_change event
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "transitions from delivery to payment" do
|
|
24
|
+
allow(persisted_order).to receive_messages(payment_required?: true)
|
|
25
|
+
persisted_order.next!
|
|
26
|
+
expect(persisted_order.state).to eq("payment")
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Spree::Order, :type => :model do
|
|
4
|
+
let(:order) { stub_model(Spree::Order) }
|
|
5
|
+
before do
|
|
6
|
+
Spree::Order.define_state_machine!
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
context "validations" do
|
|
10
|
+
context "email validation" do
|
|
11
|
+
# Regression test for #1238
|
|
12
|
+
it "o'brien@gmail.com is a valid email address" do
|
|
13
|
+
order.state = 'address'
|
|
14
|
+
order.email = "o'brien@gmail.com"
|
|
15
|
+
expect(order.error_on(:email).size).to eq(0)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
context "#save" do
|
|
21
|
+
context "when associated with a registered user" do
|
|
22
|
+
let(:user) { double(:user, :email => "test@example.com") }
|
|
23
|
+
|
|
24
|
+
before do
|
|
25
|
+
allow(order).to receive_messages :user => user
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "should assign the email address of the user" do
|
|
29
|
+
order.run_callbacks(:create)
|
|
30
|
+
expect(order.email).to eq(user.email)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
context "in the cart state" do
|
|
36
|
+
it "should not validate email address" do
|
|
37
|
+
order.state = "cart"
|
|
38
|
+
order.email = nil
|
|
39
|
+
expect(order.error_on(:email).size).to eq(0)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,764 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'spree/testing_support/order_walkthrough'
|
|
3
|
+
|
|
4
|
+
describe Spree::Order, :type => :model do
|
|
5
|
+
let(:order) { Spree::Order.new }
|
|
6
|
+
|
|
7
|
+
before { create(:store) }
|
|
8
|
+
|
|
9
|
+
def assert_state_changed(order, from, to)
|
|
10
|
+
state_change_exists = order.state_changes.where(:previous_state => from, :next_state => to).exists?
|
|
11
|
+
assert state_change_exists, "Expected order to transition from #{from} to #{to}, but didn't."
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
context "with default state machine" do
|
|
15
|
+
let(:transitions) do
|
|
16
|
+
[
|
|
17
|
+
{ :address => :delivery },
|
|
18
|
+
{ :delivery => :payment },
|
|
19
|
+
{ :payment => :confirm },
|
|
20
|
+
{ :confirm => :complete },
|
|
21
|
+
{ :payment => :complete },
|
|
22
|
+
{ :delivery => :complete }
|
|
23
|
+
]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "has the following transitions" do
|
|
27
|
+
transitions.each do |transition|
|
|
28
|
+
transition = Spree::Order.find_transition(:from => transition.keys.first, :to => transition.values.first)
|
|
29
|
+
expect(transition).not_to be_nil
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "does not have a transition from delivery to confirm" do
|
|
34
|
+
transition = Spree::Order.find_transition(:from => :delivery, :to => :confirm)
|
|
35
|
+
expect(transition).to be_nil
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it '.find_transition when contract was broken' do
|
|
39
|
+
expect(Spree::Order.find_transition({foo: :bar, baz: :dog})).to be_falsey
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it '.remove_transition' do
|
|
43
|
+
options = {:from => transitions.first.keys.first, :to => transitions.first.values.first}
|
|
44
|
+
expect(Spree::Order).to receive_messages(
|
|
45
|
+
removed_transitions: [],
|
|
46
|
+
next_event_transitions: transitions.dup
|
|
47
|
+
)
|
|
48
|
+
expect(Spree::Order.remove_transition(options)).to be_truthy
|
|
49
|
+
expect(Spree::Order.removed_transitions).to eql([options])
|
|
50
|
+
expect(Spree::Order.next_event_transitions).to_not include(transitions.first)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it '.remove_transition when contract was broken' do
|
|
54
|
+
expect(Spree::Order.remove_transition(nil)).to be_falsey
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "always return integer on checkout_step_index" do
|
|
58
|
+
expect(order.checkout_step_index("imnotthere")).to be_a Integer
|
|
59
|
+
expect(order.checkout_step_index("delivery")).to be > 0
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "passes delivery state when transitioning from address over delivery to payment" do
|
|
63
|
+
allow(order).to receive_messages :payment_required? => true
|
|
64
|
+
order.state = "address"
|
|
65
|
+
expect(order.passed_checkout_step?("delivery")).to be false
|
|
66
|
+
order.state = "delivery"
|
|
67
|
+
expect(order.passed_checkout_step?("delivery")).to be false
|
|
68
|
+
order.state = "payment"
|
|
69
|
+
expect(order.passed_checkout_step?("delivery")).to be true
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
context "#checkout_steps" do
|
|
73
|
+
context "when confirmation not required" do
|
|
74
|
+
before do
|
|
75
|
+
allow(order).to receive_messages :confirmation_required? => false
|
|
76
|
+
allow(order).to receive_messages :payment_required? => true
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
specify do
|
|
80
|
+
expect(order.checkout_steps).to eq(%w(address delivery payment complete))
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
context "when confirmation required" do
|
|
85
|
+
before do
|
|
86
|
+
allow(order).to receive_messages :confirmation_required? => true
|
|
87
|
+
allow(order).to receive_messages :payment_required? => true
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
specify do
|
|
91
|
+
expect(order.checkout_steps).to eq(%w(address delivery payment confirm complete))
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
context "when payment not required" do
|
|
96
|
+
before { allow(order).to receive_messages :payment_required? => false }
|
|
97
|
+
specify do
|
|
98
|
+
expect(order.checkout_steps).to eq(%w(address delivery complete))
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
context "when payment required" do
|
|
103
|
+
before { allow(order).to receive_messages :payment_required? => true }
|
|
104
|
+
specify do
|
|
105
|
+
expect(order.checkout_steps).to eq(%w(address delivery payment complete))
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it "starts out at cart" do
|
|
111
|
+
expect(order.state).to eq("cart")
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
context "to address" do
|
|
115
|
+
before do
|
|
116
|
+
order.email = "user@example.com"
|
|
117
|
+
order.save!
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
context "with a line item" do
|
|
121
|
+
before do
|
|
122
|
+
order.line_items << FactoryGirl.create(:line_item)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it "transitions to address" do
|
|
126
|
+
order.next!
|
|
127
|
+
assert_state_changed(order, 'cart', 'address')
|
|
128
|
+
expect(order.state).to eq("address")
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
it "doesn't raise an error if the default address is invalid" do
|
|
132
|
+
order.user = mock_model(Spree::LegacyUser, ship_address: Spree::Address.new, bill_address: Spree::Address.new)
|
|
133
|
+
expect { order.next! }.to_not raise_error
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
context "with default addresses" do
|
|
137
|
+
let(:default_address) { FactoryGirl.create(:address) }
|
|
138
|
+
|
|
139
|
+
before do
|
|
140
|
+
order.user = FactoryGirl.create(:user, "#{address_kind}_address" => default_address)
|
|
141
|
+
order.next!
|
|
142
|
+
order.reload
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
shared_examples "it cloned the default address" do
|
|
146
|
+
it do
|
|
147
|
+
default_attributes = default_address.attributes
|
|
148
|
+
order_attributes = order.send("#{address_kind}_address".to_sym).try(:attributes) || {}
|
|
149
|
+
|
|
150
|
+
expect(order_attributes.except('id', 'created_at', 'updated_at')).to eql(default_attributes.except('id', 'created_at', 'updated_at'))
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
it_behaves_like "it cloned the default address" do
|
|
155
|
+
let(:address_kind) { 'ship' }
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
it_behaves_like "it cloned the default address" do
|
|
159
|
+
let(:address_kind) { 'bill' }
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
it "cannot transition to address without any line items" do
|
|
165
|
+
expect(order.line_items).to be_blank
|
|
166
|
+
expect { order.next! }.to raise_error(StateMachines::InvalidTransition, /#{Spree.t(:there_are_no_items_for_this_order)}/)
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
context "from address" do
|
|
171
|
+
before do
|
|
172
|
+
order.state = 'address'
|
|
173
|
+
allow(order).to receive(:has_available_payment)
|
|
174
|
+
shipment = FactoryGirl.create(:shipment, :order => order)
|
|
175
|
+
order.email = "user@example.com"
|
|
176
|
+
order.save!
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
it "updates totals" do
|
|
180
|
+
allow(order).to receive_messages(:ensure_available_shipping_rates => true)
|
|
181
|
+
line_item = FactoryGirl.create(:line_item, :price => 10, :adjustment_total => 10)
|
|
182
|
+
order.line_items << line_item
|
|
183
|
+
tax_rate = create(:tax_rate, :tax_category => line_item.tax_category, :amount => 0.05)
|
|
184
|
+
allow(Spree::TaxRate).to receive_messages :match => [tax_rate]
|
|
185
|
+
FactoryGirl.create(:tax_adjustment, :adjustable => line_item, :source => tax_rate, order: order)
|
|
186
|
+
order.email = "user@example.com"
|
|
187
|
+
order.next!
|
|
188
|
+
expect(order.adjustment_total).to eq(0.5)
|
|
189
|
+
expect(order.additional_tax_total).to eq(0.5)
|
|
190
|
+
expect(order.included_tax_total).to eq(0)
|
|
191
|
+
expect(order.total).to eq(10.5)
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
it "transitions to delivery" do
|
|
195
|
+
allow(order).to receive_messages(:ensure_available_shipping_rates => true)
|
|
196
|
+
order.next!
|
|
197
|
+
assert_state_changed(order, 'address', 'delivery')
|
|
198
|
+
expect(order.state).to eq("delivery")
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
it "does not call persist_order_address if there is no address on the order" do
|
|
202
|
+
# otherwise, it will crash
|
|
203
|
+
allow(order).to receive_messages(:ensure_available_shipping_rates => true)
|
|
204
|
+
|
|
205
|
+
order.user = FactoryGirl.create(:user)
|
|
206
|
+
order.save!
|
|
207
|
+
|
|
208
|
+
expect(order.user).to_not receive(:persist_order_address).with(order)
|
|
209
|
+
order.next!
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
it "calls persist_order_address on the order's user" do
|
|
213
|
+
allow(order).to receive_messages(:ensure_available_shipping_rates => true)
|
|
214
|
+
|
|
215
|
+
order.user = FactoryGirl.create(:user)
|
|
216
|
+
order.ship_address = FactoryGirl.create(:address)
|
|
217
|
+
order.bill_address = FactoryGirl.create(:address)
|
|
218
|
+
order.save!
|
|
219
|
+
|
|
220
|
+
expect(order.user).to receive(:persist_order_address).with(order)
|
|
221
|
+
order.next!
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
it "does not call persist_order_address on the order's user for a temporary address" do
|
|
225
|
+
allow(order).to receive_messages(:ensure_available_shipping_rates => true)
|
|
226
|
+
|
|
227
|
+
order.user = FactoryGirl.create(:user)
|
|
228
|
+
order.temporary_address = true
|
|
229
|
+
order.save!
|
|
230
|
+
|
|
231
|
+
expect(order.user).to_not receive(:persist_order_address)
|
|
232
|
+
order.next!
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
context "cannot transition to delivery" do
|
|
236
|
+
context "with an existing shipment" do
|
|
237
|
+
before do
|
|
238
|
+
line_item = FactoryGirl.create(:line_item, :price => 10)
|
|
239
|
+
order.line_items << line_item
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
context "if there are no shipping rates for any shipment" do
|
|
243
|
+
it "raises an InvalidTransitionError" do
|
|
244
|
+
transition = lambda { order.next! }
|
|
245
|
+
expect(transition).to raise_error(StateMachines::InvalidTransition, /#{Spree.t(:items_cannot_be_shipped)}/)
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
it "deletes all the shipments" do
|
|
249
|
+
order.next
|
|
250
|
+
expect(order.shipments).to be_empty
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
context "to delivery" do
|
|
258
|
+
context 'when order has default selected_shipping_rate_id' do
|
|
259
|
+
let(:shipment) { create(:shipment, order: order) }
|
|
260
|
+
let(:shipping_method) { create(:shipping_method) }
|
|
261
|
+
let(:shipping_rate) { [
|
|
262
|
+
Spree::ShippingRate.create!(shipping_method: shipping_method, cost: 10.00, shipment: shipment)
|
|
263
|
+
] }
|
|
264
|
+
|
|
265
|
+
before do
|
|
266
|
+
order.state = 'address'
|
|
267
|
+
shipment.selected_shipping_rate_id = shipping_rate.first.id
|
|
268
|
+
order.email = "user@example.com"
|
|
269
|
+
order.save!
|
|
270
|
+
|
|
271
|
+
allow(order).to receive(:has_available_payment)
|
|
272
|
+
allow(order).to receive(:create_proposed_shipments)
|
|
273
|
+
allow(order).to receive(:ensure_available_shipping_rates) { true }
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
it 'should invoke set_shipment_cost' do
|
|
277
|
+
expect(order).to receive(:set_shipments_cost)
|
|
278
|
+
order.next!
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
it 'should update shipment_total' do
|
|
282
|
+
expect { order.next! }.to change{ order.shipment_total }.by(10.00)
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
context "from delivery" do
|
|
288
|
+
before do
|
|
289
|
+
order.state = 'delivery'
|
|
290
|
+
allow(order).to receive(:apply_free_shipping_promotions)
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
it "attempts to apply free shipping promotions" do
|
|
294
|
+
expect(order).to receive(:apply_free_shipping_promotions)
|
|
295
|
+
order.next!
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
context "with payment required" do
|
|
299
|
+
before do
|
|
300
|
+
allow(order).to receive_messages :payment_required? => true
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
it "transitions to payment" do
|
|
304
|
+
expect(order).to receive(:set_shipments_cost)
|
|
305
|
+
order.next!
|
|
306
|
+
assert_state_changed(order, 'delivery', 'payment')
|
|
307
|
+
expect(order.state).to eq('payment')
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
context "without payment required" do
|
|
312
|
+
before do
|
|
313
|
+
allow(order).to receive_messages :payment_required? => false
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
it "transitions to complete" do
|
|
317
|
+
order.next!
|
|
318
|
+
expect(order.state).to eq("complete")
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
context "correctly determining payment required based on shipping information" do
|
|
323
|
+
let(:shipment) do
|
|
324
|
+
FactoryGirl.create(:shipment)
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
before do
|
|
328
|
+
# Needs to be set here because we're working with a persisted order object
|
|
329
|
+
order.email = "test@example.com"
|
|
330
|
+
order.save!
|
|
331
|
+
order.shipments << shipment
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
context "with a shipment that has a price" do
|
|
335
|
+
before do
|
|
336
|
+
shipment.shipping_rates.first.update_column(:cost, 10)
|
|
337
|
+
order.set_shipments_cost
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
it "transitions to payment" do
|
|
341
|
+
order.next!
|
|
342
|
+
expect(order.state).to eq("payment")
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
context "with a shipment that is free" do
|
|
347
|
+
before do
|
|
348
|
+
shipment.shipping_rates.first.update_column(:cost, 0)
|
|
349
|
+
order.set_shipments_cost
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
it "skips payment, transitions to complete" do
|
|
353
|
+
order.next!
|
|
354
|
+
expect(order.state).to eq("complete")
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
context "to payment" do
|
|
361
|
+
before do
|
|
362
|
+
@default_credit_card = FactoryGirl.create(:credit_card)
|
|
363
|
+
order.user = mock_model(Spree::LegacyUser, default_credit_card: @default_credit_card, email: 'spree@example.org')
|
|
364
|
+
|
|
365
|
+
allow(order).to receive_messages(payment_required?: true)
|
|
366
|
+
allow(order).to receive_messages(total: 20.00)
|
|
367
|
+
order.state = 'delivery'
|
|
368
|
+
order.save!
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
it "assigns the user's default credit card" do
|
|
372
|
+
order.next!
|
|
373
|
+
order.reload
|
|
374
|
+
|
|
375
|
+
expect(order.state).to eq 'payment'
|
|
376
|
+
expect(order.payments.count).to eq 1
|
|
377
|
+
expect(order.payments.first.amount).to eq 20.00
|
|
378
|
+
expect(order.payments.first.source).to eq @default_credit_card
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
it "only generates payment if payment required" do
|
|
382
|
+
allow(order).to receive_messages(payment_required?: false)
|
|
383
|
+
order.next!
|
|
384
|
+
order.reload
|
|
385
|
+
|
|
386
|
+
expect(order.state).to eq 'complete'
|
|
387
|
+
expect(order.payments.count).to eq 0
|
|
388
|
+
end
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
context "from payment" do
|
|
392
|
+
before do
|
|
393
|
+
order.state = 'payment'
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
context "with confirmation required" do
|
|
397
|
+
before do
|
|
398
|
+
allow(order).to receive_messages :confirmation_required? => true
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
it "transitions to confirm" do
|
|
402
|
+
order.next!
|
|
403
|
+
assert_state_changed(order, 'payment', 'confirm')
|
|
404
|
+
expect(order.state).to eq("confirm")
|
|
405
|
+
end
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
context "without confirmation required" do
|
|
409
|
+
before do
|
|
410
|
+
order.email = "spree@example.com"
|
|
411
|
+
allow(order).to receive_messages :confirmation_required? => false
|
|
412
|
+
allow(order).to receive_messages :payment_required? => true
|
|
413
|
+
order.payments << FactoryGirl.create(:payment, state: payment_state, order: order)
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
context 'when there is at least one valid payment' do
|
|
417
|
+
let(:payment_state) { 'checkout' }
|
|
418
|
+
|
|
419
|
+
before do
|
|
420
|
+
expect(order).to receive(:process_payments!).once { true }
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
it "transitions to complete" do
|
|
424
|
+
order.next!
|
|
425
|
+
assert_state_changed(order, 'payment', 'complete')
|
|
426
|
+
expect(order.state).to eq('complete')
|
|
427
|
+
end
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
context 'when there is only an invalid payment' do
|
|
431
|
+
let(:payment_state) { 'failed' }
|
|
432
|
+
|
|
433
|
+
it "raises a StateMachine::InvalidTransition" do
|
|
434
|
+
expect {
|
|
435
|
+
order.next!
|
|
436
|
+
}.to raise_error(StateMachines::InvalidTransition, /#{Spree.t(:no_payment_found)}/)
|
|
437
|
+
|
|
438
|
+
expect(order.errors[:base]).to include(Spree.t(:no_payment_found))
|
|
439
|
+
end
|
|
440
|
+
end
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
# Regression test for #2028
|
|
444
|
+
context "when payment is not required" do
|
|
445
|
+
before do
|
|
446
|
+
allow(order).to receive_messages :payment_required? => false
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
it "does not call process payments" do
|
|
450
|
+
expect(order).not_to receive(:process_payments!)
|
|
451
|
+
order.next!
|
|
452
|
+
assert_state_changed(order, 'payment', 'complete')
|
|
453
|
+
expect(order.state).to eq("complete")
|
|
454
|
+
end
|
|
455
|
+
end
|
|
456
|
+
end
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
context "to complete" do
|
|
460
|
+
before do
|
|
461
|
+
order.state = 'confirm'
|
|
462
|
+
order.save!
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
context "default credit card" do
|
|
466
|
+
before do
|
|
467
|
+
order.user = FactoryGirl.create(:user)
|
|
468
|
+
order.email = 'spree@example.org'
|
|
469
|
+
order.payments << FactoryGirl.create(:payment)
|
|
470
|
+
|
|
471
|
+
# make sure we will actually capture a payment
|
|
472
|
+
allow(order).to receive_messages(payment_required?: true)
|
|
473
|
+
order.line_items << FactoryGirl.create(:line_item)
|
|
474
|
+
Spree::OrderUpdater.new(order).update
|
|
475
|
+
|
|
476
|
+
order.save!
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
it "makes the current credit card a user's default credit card" do
|
|
480
|
+
order.next!
|
|
481
|
+
expect(order.state).to eq 'complete'
|
|
482
|
+
expect(order.user.reload.default_credit_card.try(:id)).to eq(order.credit_cards.first.id)
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
it "does not assign a default credit card if temporary_credit_card is set" do
|
|
486
|
+
order.temporary_credit_card = true
|
|
487
|
+
order.next!
|
|
488
|
+
expect(order.user.reload.default_credit_card).to be_nil
|
|
489
|
+
end
|
|
490
|
+
end
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
context "subclassed order" do
|
|
494
|
+
# This causes another test above to fail, but fixing this test should make
|
|
495
|
+
# the other test pass
|
|
496
|
+
class SubclassedOrder < Spree::Order
|
|
497
|
+
checkout_flow do
|
|
498
|
+
go_to_state :payment
|
|
499
|
+
go_to_state :complete
|
|
500
|
+
end
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
skip "should only call default transitions once when checkout_flow is redefined" do
|
|
504
|
+
order = SubclassedOrder.new
|
|
505
|
+
allow(order).to receive_messages :payment_required? => true
|
|
506
|
+
expect(order).to receive(:process_payments!).once
|
|
507
|
+
order.state = "payment"
|
|
508
|
+
order.next!
|
|
509
|
+
assert_state_changed(order, 'payment', 'complete')
|
|
510
|
+
expect(order.state).to eq("complete")
|
|
511
|
+
end
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
context "re-define checkout flow" do
|
|
515
|
+
before do
|
|
516
|
+
@old_checkout_flow = Spree::Order.checkout_flow
|
|
517
|
+
Spree::Order.class_eval do
|
|
518
|
+
checkout_flow do
|
|
519
|
+
go_to_state :payment
|
|
520
|
+
go_to_state :complete
|
|
521
|
+
end
|
|
522
|
+
end
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
after do
|
|
526
|
+
Spree::Order.checkout_flow(&@old_checkout_flow)
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
it "should not keep old event transitions when checkout_flow is redefined" do
|
|
530
|
+
expect(Spree::Order.next_event_transitions).to eq([{:cart=>:payment}, {:payment=>:complete}])
|
|
531
|
+
end
|
|
532
|
+
|
|
533
|
+
it "should not keep old events when checkout_flow is redefined" do
|
|
534
|
+
state_machine = Spree::Order.state_machine
|
|
535
|
+
expect(state_machine.states.any? { |s| s.name == :address }).to be false
|
|
536
|
+
known_states = state_machine.events[:next].branches.map(&:known_states).flatten
|
|
537
|
+
expect(known_states).not_to include(:address)
|
|
538
|
+
expect(known_states).not_to include(:delivery)
|
|
539
|
+
expect(known_states).not_to include(:confirm)
|
|
540
|
+
end
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
# Regression test for #3665
|
|
544
|
+
context "with only a complete step" do
|
|
545
|
+
before do
|
|
546
|
+
@old_checkout_flow = Spree::Order.checkout_flow
|
|
547
|
+
Spree::Order.class_eval do
|
|
548
|
+
checkout_flow do
|
|
549
|
+
go_to_state :complete
|
|
550
|
+
end
|
|
551
|
+
end
|
|
552
|
+
end
|
|
553
|
+
|
|
554
|
+
after do
|
|
555
|
+
Spree::Order.checkout_flow(&@old_checkout_flow)
|
|
556
|
+
end
|
|
557
|
+
|
|
558
|
+
it "does not attempt to process payments" do
|
|
559
|
+
allow(order).to receive_message_chain(:line_items, :present?) { true }
|
|
560
|
+
allow(order).to receive(:ensure_line_items_are_in_stock) { true }
|
|
561
|
+
allow(order).to receive(:ensure_line_item_variants_are_not_deleted) { true }
|
|
562
|
+
expect(order).not_to receive(:payment_required?)
|
|
563
|
+
expect(order).not_to receive(:process_payments!)
|
|
564
|
+
order.next!
|
|
565
|
+
assert_state_changed(order, 'cart', 'complete')
|
|
566
|
+
end
|
|
567
|
+
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
context "insert checkout step" do
|
|
571
|
+
before do
|
|
572
|
+
@old_checkout_flow = Spree::Order.checkout_flow
|
|
573
|
+
Spree::Order.class_eval do
|
|
574
|
+
insert_checkout_step :new_step, before: :address
|
|
575
|
+
end
|
|
576
|
+
end
|
|
577
|
+
|
|
578
|
+
after do
|
|
579
|
+
Spree::Order.checkout_flow(&@old_checkout_flow)
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
it "should maintain removed transitions" do
|
|
583
|
+
transition = Spree::Order.find_transition(:from => :delivery, :to => :confirm)
|
|
584
|
+
expect(transition).to be_nil
|
|
585
|
+
end
|
|
586
|
+
|
|
587
|
+
context "before" do
|
|
588
|
+
before do
|
|
589
|
+
Spree::Order.class_eval do
|
|
590
|
+
insert_checkout_step :before_address, before: :address
|
|
591
|
+
end
|
|
592
|
+
end
|
|
593
|
+
|
|
594
|
+
specify do
|
|
595
|
+
order = Spree::Order.new
|
|
596
|
+
expect(order.checkout_steps).to eq(%w(new_step before_address address delivery complete))
|
|
597
|
+
end
|
|
598
|
+
end
|
|
599
|
+
|
|
600
|
+
context "after" do
|
|
601
|
+
before do
|
|
602
|
+
Spree::Order.class_eval do
|
|
603
|
+
insert_checkout_step :after_address, after: :address
|
|
604
|
+
end
|
|
605
|
+
end
|
|
606
|
+
|
|
607
|
+
specify do
|
|
608
|
+
order = Spree::Order.new
|
|
609
|
+
expect(order.checkout_steps).to eq(%w(new_step address after_address delivery complete))
|
|
610
|
+
end
|
|
611
|
+
end
|
|
612
|
+
end
|
|
613
|
+
|
|
614
|
+
context "remove checkout step" do
|
|
615
|
+
before do
|
|
616
|
+
@old_checkout_flow = Spree::Order.checkout_flow
|
|
617
|
+
Spree::Order.class_eval do
|
|
618
|
+
remove_checkout_step :address
|
|
619
|
+
end
|
|
620
|
+
end
|
|
621
|
+
|
|
622
|
+
after do
|
|
623
|
+
Spree::Order.checkout_flow(&@old_checkout_flow)
|
|
624
|
+
end
|
|
625
|
+
|
|
626
|
+
it "should maintain removed transitions" do
|
|
627
|
+
transition = Spree::Order.find_transition(:from => :delivery, :to => :confirm)
|
|
628
|
+
expect(transition).to be_nil
|
|
629
|
+
end
|
|
630
|
+
|
|
631
|
+
specify do
|
|
632
|
+
order = Spree::Order.new
|
|
633
|
+
expect(order.checkout_steps).to eq(%w(delivery complete))
|
|
634
|
+
end
|
|
635
|
+
end
|
|
636
|
+
|
|
637
|
+
describe 'update_from_params' do
|
|
638
|
+
let(:permitted_params) { {} }
|
|
639
|
+
let(:params) { {} }
|
|
640
|
+
|
|
641
|
+
it 'calls update_atributes without order params' do
|
|
642
|
+
expect(order).to receive(:update_attributes).with({})
|
|
643
|
+
order.update_from_params( params, permitted_params)
|
|
644
|
+
end
|
|
645
|
+
|
|
646
|
+
it 'runs the callbacks' do
|
|
647
|
+
expect(order).to receive(:run_callbacks).with(:updating_from_params)
|
|
648
|
+
order.update_from_params( params, permitted_params)
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
context "passing a credit card" do
|
|
652
|
+
let(:permitted_params) do
|
|
653
|
+
Spree::PermittedAttributes.checkout_attributes +
|
|
654
|
+
[payments_attributes: Spree::PermittedAttributes.payment_attributes]
|
|
655
|
+
end
|
|
656
|
+
|
|
657
|
+
let(:credit_card) { create(:credit_card, user_id: order.user_id) }
|
|
658
|
+
|
|
659
|
+
let(:params) do
|
|
660
|
+
ActionController::Parameters.new(
|
|
661
|
+
order: { payments_attributes: [{payment_method_id: 1}], existing_card: credit_card.id },
|
|
662
|
+
cvc_confirm: "737",
|
|
663
|
+
payment_source: {
|
|
664
|
+
"1" => { name: "Luis Braga",
|
|
665
|
+
number: "4111 1111 1111 1111",
|
|
666
|
+
expiry: "06 / 2016",
|
|
667
|
+
verification_value: "737",
|
|
668
|
+
cc_type: "" }
|
|
669
|
+
}
|
|
670
|
+
)
|
|
671
|
+
end
|
|
672
|
+
|
|
673
|
+
before { order.user_id = 3 }
|
|
674
|
+
|
|
675
|
+
it "sets confirmation value when its available via :cvc_confirm" do
|
|
676
|
+
allow(Spree::CreditCard).to receive_messages find: credit_card
|
|
677
|
+
expect(credit_card).to receive(:verification_value=)
|
|
678
|
+
order.update_from_params(params, permitted_params)
|
|
679
|
+
end
|
|
680
|
+
|
|
681
|
+
it "sets existing card as source for new payment" do
|
|
682
|
+
expect {
|
|
683
|
+
order.update_from_params(params, permitted_params)
|
|
684
|
+
}.to change { Spree::Payment.count }.by(1)
|
|
685
|
+
|
|
686
|
+
expect(Spree::Payment.last.source).to eq credit_card
|
|
687
|
+
end
|
|
688
|
+
|
|
689
|
+
it "sets request_env on payment" do
|
|
690
|
+
request_env = { "USER_AGENT" => "Firefox" }
|
|
691
|
+
|
|
692
|
+
expected_hash = { "payments_attributes" => [hash_including("request_env" => request_env)] }
|
|
693
|
+
expect(order).to receive(:update_attributes).with expected_hash
|
|
694
|
+
|
|
695
|
+
order.update_from_params(params, permitted_params, request_env)
|
|
696
|
+
end
|
|
697
|
+
|
|
698
|
+
it "dont let users mess with others users cards" do
|
|
699
|
+
credit_card.update_column :user_id, 5
|
|
700
|
+
|
|
701
|
+
expect {
|
|
702
|
+
order.update_from_params(params, permitted_params)
|
|
703
|
+
}.to raise_error
|
|
704
|
+
end
|
|
705
|
+
end
|
|
706
|
+
|
|
707
|
+
context 'has params' do
|
|
708
|
+
let(:permitted_params) { [ :good_param ] }
|
|
709
|
+
let(:params) { ActionController::Parameters.new(order: { bad_param: 'okay' } ) }
|
|
710
|
+
|
|
711
|
+
it 'does not let through unpermitted attributes' do
|
|
712
|
+
expect(order).to receive(:update_attributes).with({})
|
|
713
|
+
order.update_from_params(params, permitted_params)
|
|
714
|
+
end
|
|
715
|
+
|
|
716
|
+
context 'has existing_card param' do
|
|
717
|
+
let(:permitted_params) do
|
|
718
|
+
Spree::PermittedAttributes.checkout_attributes +
|
|
719
|
+
[payments_attributes: Spree::PermittedAttributes.payment_attributes]
|
|
720
|
+
end
|
|
721
|
+
let(:credit_card) { create(:credit_card, user_id: order.user_id) }
|
|
722
|
+
let(:params) do
|
|
723
|
+
ActionController::Parameters.new(
|
|
724
|
+
order: { payments_attributes: [{payment_method_id: 1}], existing_card: credit_card.id }
|
|
725
|
+
)
|
|
726
|
+
end
|
|
727
|
+
|
|
728
|
+
before do
|
|
729
|
+
Dummy::Application.config.action_controller.action_on_unpermitted_parameters = :raise
|
|
730
|
+
order.user_id = 3
|
|
731
|
+
end
|
|
732
|
+
|
|
733
|
+
after do
|
|
734
|
+
Dummy::Application.config.action_controller.action_on_unpermitted_parameters = :log
|
|
735
|
+
end
|
|
736
|
+
|
|
737
|
+
it 'does not attempt to permit existing_card' do
|
|
738
|
+
expect {
|
|
739
|
+
order.update_from_params(params, permitted_params)
|
|
740
|
+
}.not_to raise_error
|
|
741
|
+
end
|
|
742
|
+
end
|
|
743
|
+
|
|
744
|
+
context 'has allowed params' do
|
|
745
|
+
let(:params) { ActionController::Parameters.new(order: { good_param: 'okay' } ) }
|
|
746
|
+
|
|
747
|
+
it 'accepts permitted attributes' do
|
|
748
|
+
expect(order).to receive(:update_attributes).with({"good_param" => 'okay'})
|
|
749
|
+
order.update_from_params(params, permitted_params)
|
|
750
|
+
end
|
|
751
|
+
end
|
|
752
|
+
|
|
753
|
+
context 'callbacks halt' do
|
|
754
|
+
before do
|
|
755
|
+
expect(order).to receive(:update_params_payment_source).and_return false
|
|
756
|
+
end
|
|
757
|
+
it 'does not let through unpermitted attributes' do
|
|
758
|
+
expect(order).not_to receive(:update_attributes).with({})
|
|
759
|
+
order.update_from_params(params, permitted_params)
|
|
760
|
+
end
|
|
761
|
+
end
|
|
762
|
+
end
|
|
763
|
+
end
|
|
764
|
+
end
|