solidus_core 2.0.3 → 2.1.0.beta1
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/README.md +62 -3
- data/app/assets/javascripts/spree.js.coffee.erb +4 -1
- data/app/helpers/spree/base_helper.rb +7 -48
- data/app/models/spree/address.rb +5 -1
- data/app/models/spree/adjustment.rb +3 -3
- data/app/models/spree/app_configuration.rb +13 -0
- data/app/models/spree/calculator.rb +3 -2
- data/app/models/spree/calculator/default_tax.rb +6 -10
- data/app/models/spree/calculator/flat_percent_item_total.rb +0 -4
- data/app/models/spree/calculator/flat_rate.rb +0 -4
- data/app/models/spree/calculator/flexi_rate.rb +0 -4
- data/app/models/spree/calculator/free_shipping.rb +0 -3
- data/app/models/spree/calculator/percent_on_line_item.rb +0 -4
- data/app/models/spree/calculator/percent_per_item.rb +0 -4
- data/app/models/spree/calculator/price_sack.rb +0 -4
- data/app/models/spree/calculator/returns/default_refund_amount.rb +0 -3
- data/app/models/spree/calculator/shipping/flat_percent_item_total.rb +0 -4
- data/app/models/spree/calculator/shipping/flat_rate.rb +0 -4
- data/app/models/spree/calculator/shipping/flexi_rate.rb +0 -4
- data/app/models/spree/calculator/shipping/per_item.rb +0 -4
- data/app/models/spree/calculator/shipping/price_sack.rb +0 -4
- data/app/models/spree/calculator/tiered_flat_rate.rb +0 -4
- data/app/models/spree/calculator/tiered_percent.rb +0 -4
- data/app/models/spree/credit_card.rb +27 -14
- data/app/models/spree/gateway.rb +4 -0
- data/app/models/spree/inventory_unit.rb +2 -0
- data/app/models/spree/line_item.rb +31 -26
- data/app/models/spree/option_type.rb +0 -3
- data/app/models/spree/order.rb +28 -31
- data/app/models/spree/order/checkout.rb +0 -2
- data/app/models/spree/order_contents.rb +0 -45
- data/app/models/spree/order_merger.rb +6 -6
- data/app/models/spree/order_update_attributes.rb +0 -2
- data/app/models/spree/order_updater.rb +91 -13
- data/app/models/spree/payment.rb +9 -2
- data/app/models/spree/payment/processing.rb +15 -9
- data/app/models/spree/payment_method.rb +48 -5
- data/app/models/spree/price.rb +7 -9
- data/app/models/spree/product.rb +1 -25
- data/app/models/spree/promotion.rb +22 -14
- data/app/models/spree/promotion/actions/create_adjustment.rb +12 -1
- data/app/models/spree/promotion/actions/create_item_adjustments.rb +15 -1
- data/app/models/spree/promotion/actions/create_quantity_adjustments.rb +5 -3
- data/app/models/spree/promotion/actions/free_shipping.rb +14 -0
- data/app/models/spree/promotion/rules/taxon.rb +7 -2
- data/app/models/spree/promotion/rules/user_role.rb +43 -0
- data/app/models/spree/promotion_action.rb +19 -2
- data/app/models/spree/promotion_handler/coupon.rb +1 -4
- data/app/models/spree/promotion_handler/free_shipping.rb +22 -17
- data/app/models/spree/promotion_rule_role.rb +6 -0
- data/app/models/spree/property.rb +0 -3
- data/app/models/spree/return_authorization.rb +2 -0
- data/app/models/spree/shipment.rb +5 -21
- data/app/models/spree/shipping_method.rb +23 -2
- data/app/models/spree/shipping_rate.rb +3 -0
- data/app/models/spree/stock/estimator.rb +1 -1
- data/app/models/spree/stock_location.rb +3 -0
- data/app/models/spree/store.rb +7 -0
- data/app/models/spree/tax/item_adjuster.rb +27 -12
- data/app/models/spree/tax/order_adjuster.rb +2 -5
- data/app/models/spree/tax/tax_helpers.rb +4 -8
- data/app/models/spree/tax_rate.rb +1 -15
- data/app/models/spree/taxon.rb +0 -3
- data/app/models/spree/transfer_item.rb +1 -1
- data/app/models/spree/user_class_handle.rb +14 -9
- data/app/models/spree/variant/pricing_options.rb +1 -1
- data/app/models/spree/wallet/add_payment_sources_to_wallet.rb +1 -1
- data/app/models/spree/zone.rb +20 -13
- data/config/locales/en.yml +144 -62
- data/db/migrate/20120831092320_spree_one_two.rb +0 -7
- data/db/migrate/20150723224133_remove_unnecessary_indexes.rb +0 -2
- data/db/migrate/20160924135758_remove_is_default_from_prices.rb +5 -0
- data/db/migrate/20161009141333_remove_currency_from_line_items.rb +5 -0
- data/db/migrate/20161014221052_add_available_to_columns_and_remove_display_on_from_payment_methods.rb +28 -0
- data/db/migrate/20161123154034_add_available_to_users_and_remove_display_on_from_shipping_methods.rb +20 -0
- data/lib/generators/spree/custom_user/templates/authentication_helpers.rb.tt +4 -0
- data/lib/generators/spree/dummy/dummy_generator.rb +0 -2
- data/lib/spree/core.rb +0 -5
- data/lib/spree/core/controller_helpers/pricing.rb +2 -1
- data/lib/spree/core/engine.rb +14 -0
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/deprecation.rb +1 -1
- data/lib/spree/localized_number.rb +3 -2
- data/lib/spree/permission_sets/configuration_display.rb +0 -1
- data/lib/spree/permission_sets/configuration_management.rb +0 -1
- data/lib/spree/permission_sets/product_display.rb +0 -1
- data/lib/spree/permission_sets/product_management.rb +0 -1
- data/lib/spree/permission_sets/user_management.rb +2 -4
- data/lib/spree/permitted_attributes.rb +3 -2
- data/lib/spree/testing_support/capybara_ext.rb +0 -12
- data/lib/spree/testing_support/factories/address_factory.rb +1 -1
- data/lib/spree/testing_support/factories/line_item_factory.rb +0 -1
- data/lib/spree/testing_support/factories/payment_factory.rb +4 -0
- data/lib/spree/testing_support/factories/payment_method_factory.rb +8 -1
- data/lib/spree/testing_support/factories/user_factory.rb +2 -2
- data/solidus_core.gemspec +4 -3
- data/spec/helpers/base_helper_spec.rb +0 -40
- data/spec/lib/spree/core/controller_helpers/pricing_spec.rb +16 -0
- data/spec/lib/spree/core/importer/order_spec.rb +27 -18
- data/spec/lib/spree/core/price_migrator_spec.rb +3 -1
- data/spec/lib/spree/core/testing_support/factories/order_factory_spec.rb +16 -0
- data/spec/lib/spree/core/unreturned_item_charger_spec.rb +0 -2
- data/spec/lib/tasks/exchanges_spec.rb +4 -2
- data/spec/lib/tasks/migrations/create_vat_prices_spec.rb +5 -3
- data/spec/models/spree/adjustment_spec.rb +136 -0
- data/spec/models/spree/calculator/default_tax_spec.rb +13 -7
- data/spec/models/spree/calculator/flat_percent_item_total_spec.rb +3 -0
- data/spec/models/spree/calculator/flat_rate_spec.rb +3 -0
- data/spec/models/spree/calculator/flexi_rate_spec.rb +3 -0
- data/spec/models/spree/calculator/free_shipping_spec.rb +6 -0
- data/spec/models/spree/calculator/percent_on_line_item_spec.rb +9 -4
- data/spec/models/spree/calculator/percent_per_item_spec.rb +10 -0
- data/spec/models/spree/calculator/price_sack_spec.rb +3 -0
- data/spec/models/spree/calculator/refunds/default_refund_amount_spec.rb +3 -0
- data/spec/models/spree/calculator/shipping/flat_percent_item_total_spec.rb +3 -0
- data/spec/models/spree/calculator/shipping/flat_rate_spec.rb +3 -0
- data/spec/models/spree/calculator/shipping/flexi_rate_spec.rb +3 -0
- data/spec/models/spree/calculator/shipping/per_item_spec.rb +3 -0
- data/spec/models/spree/calculator/shipping/price_sack_spec.rb +4 -1
- data/spec/models/spree/calculator/tiered_flat_rate_spec.rb +3 -0
- data/spec/models/spree/calculator/tiered_percent_spec.rb +3 -0
- data/spec/models/spree/credit_card_spec.rb +27 -1
- data/spec/models/spree/line_item_spec.rb +58 -65
- data/spec/models/spree/order/checkout_spec.rb +2 -1
- data/spec/models/spree/order/payment_spec.rb +9 -10
- data/spec/models/spree/order/tax_spec.rb +22 -7
- data/spec/models/spree/order/updating_spec.rb +1 -3
- data/spec/models/spree/order_cancellations_spec.rb +6 -4
- data/spec/models/spree/order_contents_spec.rb +34 -50
- data/spec/models/spree/order_inventory_spec.rb +3 -5
- data/spec/models/spree/order_merger_spec.rb +20 -0
- data/spec/models/spree/order_spec.rb +28 -64
- data/spec/models/spree/order_update_attributes_spec.rb +1 -5
- data/spec/models/spree/order_updater_spec.rb +251 -0
- data/spec/models/spree/payment_method_spec.rb +178 -28
- data/spec/models/spree/payment_spec.rb +35 -19
- data/spec/models/spree/permission_sets/configuration_display.rb +0 -4
- data/spec/models/spree/permission_sets/configuration_management_spec.rb +0 -2
- data/spec/models/spree/permission_sets/product_display_spec.rb +0 -4
- data/spec/models/spree/permission_sets/product_management_spec.rb +0 -2
- data/spec/models/spree/permission_sets/user_management_spec.rb +9 -2
- data/spec/models/spree/price_spec.rb +16 -1
- data/spec/models/spree/product_spec.rb +0 -75
- data/spec/models/spree/promotion/actions/create_adjustment_spec.rb +20 -0
- data/spec/models/spree/promotion/actions/create_item_adjustments_spec.rb +39 -15
- data/spec/models/spree/promotion/actions/create_quantity_adjustments_spec.rb +203 -22
- data/spec/models/spree/promotion/actions/free_shipping_spec.rb +22 -3
- data/spec/models/spree/promotion/rules/taxon_spec.rb +26 -0
- data/spec/models/spree/promotion/rules/user_role_spec.rb +86 -0
- data/spec/models/spree/promotion_action_spec.rb +38 -0
- data/spec/models/spree/promotion_handler/coupon_spec.rb +36 -33
- data/spec/models/spree/promotion_handler/free_shipping_spec.rb +21 -22
- data/spec/models/spree/promotion_spec.rb +46 -6
- data/spec/models/spree/reimbursement_spec.rb +1 -1
- data/spec/models/spree/reimbursement_tax_calculator_spec.rb +2 -2
- data/spec/models/spree/shipment_spec.rb +68 -50
- data/spec/models/spree/shipping_method_spec.rb +41 -0
- data/spec/models/spree/shipping_rate_spec.rb +9 -3
- data/spec/models/spree/stock/estimator_spec.rb +4 -2
- data/spec/models/spree/store_credit_spec.rb +3 -3
- data/spec/models/spree/tax/item_adjuster_spec.rb +31 -21
- data/spec/models/spree/tax/order_adjuster_spec.rb +6 -10
- data/spec/models/spree/tax/taxation_integration_spec.rb +19 -0
- data/spec/models/spree/tax_rate_spec.rb +5 -26
- data/spec/models/spree/transfer_item_spec.rb +11 -0
- data/spec/models/spree/variant/pricing_options_spec.rb +7 -17
- data/spec/models/spree/variant_spec.rb +2 -4
- data/spec/models/spree/zone_spec.rb +60 -20
- data/spec/shared_examples/calculator_shared_examples.rb +8 -0
- metadata +19 -24
- data/app/models/spree/item_adjustments.rb +0 -89
- data/app/models/spree/option_type_prototype.rb +0 -6
- data/app/models/spree/property_prototype.rb +0 -6
- data/app/models/spree/prototype.rb +0 -14
- data/app/models/spree/prototype_taxon.rb +0 -6
- data/app/models/spree/tracker.rb +0 -8
- data/db/migrate/20150128032538_remove_environment_from_tracker.rb +0 -6
- data/lib/generators/spree/dummy/templates/initializers/custom_user.rb +0 -1
- data/lib/spree/core/delegate_belongs_to.rb +0 -94
- data/lib/spree/testing_support/factories/prototype_factory.rb +0 -8
- data/lib/spree/testing_support/factories/tracker_factory.rb +0 -6
- data/spec/lib/spree/core/delegate_belongs_to_spec.rb +0 -24
- data/spec/lib/spree/core/testing_support/factories/prototype_factory_spec.rb +0 -12
- data/spec/lib/spree/core/testing_support/factories/tracker_factory_spec.rb +0 -12
- data/spec/models/spree/item_adjustments_spec.rb +0 -306
- data/spec/models/spree/tracker_spec.rb +0 -21
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
3
|
describe Spree::Order, type: :model do
|
|
4
|
-
let(:order) {
|
|
4
|
+
let(:order) { create(:order) }
|
|
5
5
|
|
|
6
6
|
context "#update!" do
|
|
7
|
-
let(:line_items) { [mock_model(Spree::LineItem, amount: 5)] }
|
|
8
|
-
|
|
9
7
|
context "when there are update hooks" do
|
|
10
8
|
before { Spree::Order.register_update_hook :foo }
|
|
11
9
|
after { Spree::Order.update_hooks.clear }
|
|
@@ -134,17 +134,19 @@ describe Spree::OrderCancellations do
|
|
|
134
134
|
let(:line_item) { order.line_items.to_a.first }
|
|
135
135
|
let(:inventory_unit_1) { line_item.inventory_units[0] }
|
|
136
136
|
let(:inventory_unit_2) { line_item.inventory_units[1] }
|
|
137
|
+
let(:promotion) { create(:promotion, :with_line_item_adjustment) }
|
|
138
|
+
let(:promotion_action) { promotion.actions[0] }
|
|
137
139
|
|
|
138
140
|
before do
|
|
139
141
|
order.contents.add(line_item.variant)
|
|
140
142
|
|
|
141
143
|
# make the total $1.67 so it divides unevenly
|
|
142
144
|
line_item.adjustments.create!(
|
|
143
|
-
source_type: 'Spree::TaxRate',
|
|
144
145
|
order: order,
|
|
145
146
|
amount: 0.01,
|
|
146
|
-
label: 'some
|
|
147
|
-
|
|
147
|
+
label: 'some promo',
|
|
148
|
+
source: promotion_action,
|
|
149
|
+
finalized: true,
|
|
148
150
|
)
|
|
149
151
|
order.update!
|
|
150
152
|
end
|
|
@@ -154,7 +156,7 @@ describe Spree::OrderCancellations do
|
|
|
154
156
|
order.cancellations.short_ship([inventory_unit_2])
|
|
155
157
|
expect(line_item.adjustments.map(&:amount)).to match_array(
|
|
156
158
|
[
|
|
157
|
-
0.01,
|
|
159
|
+
0.01, # promo adjustment
|
|
158
160
|
-0.84, # short ship 1
|
|
159
161
|
-0.83, # short ship 2
|
|
160
162
|
]
|
|
@@ -2,12 +2,12 @@ require 'spec_helper'
|
|
|
2
2
|
|
|
3
3
|
describe Spree::OrderContents, type: :model do
|
|
4
4
|
let!(:store) { create :store }
|
|
5
|
-
let(:order) {
|
|
5
|
+
let(:order) { create(:order) }
|
|
6
6
|
let(:variant) { create(:variant) }
|
|
7
7
|
let!(:stock_location) { variant.stock_locations.first }
|
|
8
8
|
let(:stock_location_2) { create(:stock_location) }
|
|
9
9
|
|
|
10
|
-
subject { described_class.new(order) }
|
|
10
|
+
subject(:order_contents) { described_class.new(order) }
|
|
11
11
|
|
|
12
12
|
context "#add" do
|
|
13
13
|
context 'given quantity is not explicitly provided' do
|
|
@@ -96,6 +96,38 @@ describe Spree::OrderContents, type: :model do
|
|
|
96
96
|
include_context "discount changes order total"
|
|
97
97
|
end
|
|
98
98
|
end
|
|
99
|
+
|
|
100
|
+
describe 'tax calculations' do
|
|
101
|
+
let!(:zone) { create(:global_zone) }
|
|
102
|
+
let!(:tax_rate) do
|
|
103
|
+
create(:tax_rate, zone: zone, tax_category: variant.tax_category)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
context 'when the order has a taxable address' do
|
|
107
|
+
before do
|
|
108
|
+
expect(order.tax_address.country_id).to be_present
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it 'creates a tax adjustment' do
|
|
112
|
+
order_contents.add(variant)
|
|
113
|
+
line_item = order.find_line_item_by_variant(variant)
|
|
114
|
+
expect(line_item.adjustments.tax.count).to eq(1)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
context 'when the order does not have a taxable address' do
|
|
119
|
+
before do
|
|
120
|
+
order.update_attributes!(ship_address: nil, bill_address: nil)
|
|
121
|
+
expect(order.tax_address.country_id).to be_nil
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
it 'creates a tax adjustment' do
|
|
125
|
+
order_contents.add(variant)
|
|
126
|
+
line_item = order.find_line_item_by_variant(variant)
|
|
127
|
+
expect(line_item.adjustments.tax.count).to eq(0)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
99
131
|
end
|
|
100
132
|
|
|
101
133
|
context "#remove" do
|
|
@@ -224,54 +256,6 @@ describe Spree::OrderContents, type: :model do
|
|
|
224
256
|
}.to change { subject.order.total }
|
|
225
257
|
end
|
|
226
258
|
|
|
227
|
-
context "given an order with existing addresses" do
|
|
228
|
-
let(:default_address) { create :address, state_code: "NY", zipcode: "17402" }
|
|
229
|
-
let(:order_with_address ) { create :order, ship_address: default_address, bill_address: default_address }
|
|
230
|
-
|
|
231
|
-
subject { described_class.new(order_with_address) }
|
|
232
|
-
|
|
233
|
-
context "when an address in a potentially different tax zone is supplied " do
|
|
234
|
-
let(:updated_address) { build :address, state_code: "AL", zipcode: "64092" }
|
|
235
|
-
|
|
236
|
-
let(:params) do
|
|
237
|
-
{ ship_address_attributes: updated_address.value_attributes, bill_address_attributes: updated_address.value_attributes }
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
it "updates tax adjustments" do
|
|
241
|
-
expect(subject.order).to receive(:create_tax_charge!)
|
|
242
|
-
subject.update_cart params
|
|
243
|
-
end
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
context "when an address in potentially the same tax zone is supplied" do
|
|
247
|
-
let(:updated_address) { build :address, state_code: "NY", zipcode: "17402", firstname: 'Robert' }
|
|
248
|
-
|
|
249
|
-
let(:params) do
|
|
250
|
-
{ ship_address_attributes: updated_address.value_attributes, bill_address_attributes: updated_address.value_attributes }
|
|
251
|
-
end
|
|
252
|
-
|
|
253
|
-
it "does not updates tax adjustments" do
|
|
254
|
-
expect(subject.order).not_to receive(:create_tax_charge!)
|
|
255
|
-
subject.update_cart params
|
|
256
|
-
end
|
|
257
|
-
end
|
|
258
|
-
end
|
|
259
|
-
|
|
260
|
-
context "given an order with no existing addresses" do
|
|
261
|
-
context "when an address is supplied" do
|
|
262
|
-
let(:updated_address) { build :address, state_code: "CA", zipcode: "14902" }
|
|
263
|
-
|
|
264
|
-
let(:params) do
|
|
265
|
-
{ ship_address_attributes: updated_address.attributes, bill_address_attributes: updated_address.value_attributes }
|
|
266
|
-
end
|
|
267
|
-
|
|
268
|
-
it "does not updates tax adjustments" do
|
|
269
|
-
expect(subject.order).not_to receive(:create_tax_charge!)
|
|
270
|
-
subject.update_cart params
|
|
271
|
-
end
|
|
272
|
-
end
|
|
273
|
-
end
|
|
274
|
-
|
|
275
259
|
context "submits item quantity 0" do
|
|
276
260
|
let(:params) do
|
|
277
261
|
{ line_items_attributes: {
|
|
@@ -201,12 +201,10 @@ describe Spree::OrderInventory, type: :model do
|
|
|
201
201
|
end
|
|
202
202
|
|
|
203
203
|
it 'should destroy self if not inventory units remain' do
|
|
204
|
-
shipment.inventory_units
|
|
205
|
-
shipment.
|
|
204
|
+
allow(shipment.inventory_units).to receive_messages(count: 0)
|
|
205
|
+
expect(shipment).to receive(:destroy)
|
|
206
206
|
|
|
207
|
-
expect
|
|
208
|
-
expect(subject.send(:remove_from_shipment, shipment, 1)).to eq(1)
|
|
209
|
-
}.to change{ order.shipments.count }.from(1).to(0)
|
|
207
|
+
expect(subject.send(:remove_from_shipment, shipment, 1)).to eq(1)
|
|
210
208
|
end
|
|
211
209
|
|
|
212
210
|
context "inventory unit line item and variant points to different products" do
|
|
@@ -43,6 +43,26 @@ module Spree
|
|
|
43
43
|
end
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
+
context 'merging together two orders with multiple currencies line items' do
|
|
47
|
+
let(:order_2) { Spree::Order.create(currency: 'JPY') }
|
|
48
|
+
let(:variant_2) { create(:variant) }
|
|
49
|
+
|
|
50
|
+
before do
|
|
51
|
+
Spree::Price.create(variant: variant_2, amount: 10, currency: 'JPY')
|
|
52
|
+
order_1.contents.add(variant, 1)
|
|
53
|
+
order_2.contents.add(variant_2.reload, 1)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'rejects other order line items' do
|
|
57
|
+
subject.merge!(order_2, user)
|
|
58
|
+
expect(order_1.line_items.count).to eq(1)
|
|
59
|
+
|
|
60
|
+
line_item = order_1.line_items.first
|
|
61
|
+
expect(line_item.quantity).to eq(1)
|
|
62
|
+
expect(line_item.variant_id).to eq(variant.id)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
46
66
|
context "merging using extension-specific line_item_comparison_hooks" do
|
|
47
67
|
before do
|
|
48
68
|
Spree::Order.register_line_item_comparison_hook(:foos_match)
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
|
-
class FakeCalculator < Spree::Calculator
|
|
4
|
-
def compute(_computable)
|
|
5
|
-
5
|
|
6
|
-
end
|
|
7
|
-
end
|
|
8
|
-
|
|
9
3
|
describe Spree::Order, type: :model do
|
|
10
4
|
let(:store) { build_stubbed(:store) }
|
|
11
5
|
let(:user) { stub_model(Spree::LegacyUser, email: "spree@example.com") }
|
|
@@ -516,7 +510,8 @@ describe Spree::Order, type: :model do
|
|
|
516
510
|
payment_method = Spree::PaymentMethod.create!({
|
|
517
511
|
name: "Fake",
|
|
518
512
|
active: true,
|
|
519
|
-
|
|
513
|
+
available_to_users: true,
|
|
514
|
+
available_to_admin: false
|
|
520
515
|
})
|
|
521
516
|
expect(order.available_payment_methods).to include(payment_method)
|
|
522
517
|
end
|
|
@@ -525,16 +520,18 @@ describe Spree::Order, type: :model do
|
|
|
525
520
|
payment_method = Spree::PaymentMethod.create!({
|
|
526
521
|
name: "Fake",
|
|
527
522
|
active: true,
|
|
528
|
-
|
|
523
|
+
available_to_users: true,
|
|
524
|
+
available_to_admin: true
|
|
529
525
|
})
|
|
530
526
|
expect(order.available_payment_methods).to include(payment_method)
|
|
531
527
|
end
|
|
532
528
|
|
|
533
|
-
it "does not include a payment method twice
|
|
529
|
+
it "does not include a payment method twice" do
|
|
534
530
|
payment_method = Spree::PaymentMethod.create!({
|
|
535
531
|
name: "Fake",
|
|
536
532
|
active: true,
|
|
537
|
-
|
|
533
|
+
available_to_users: true,
|
|
534
|
+
available_to_admin: true
|
|
538
535
|
})
|
|
539
536
|
expect(order.available_payment_methods.count).to eq(1)
|
|
540
537
|
expect(order.available_payment_methods).to include(payment_method)
|
|
@@ -543,8 +540,10 @@ describe Spree::Order, type: :model do
|
|
|
543
540
|
context "with more than one payment method" do
|
|
544
541
|
subject { order.available_payment_methods }
|
|
545
542
|
|
|
546
|
-
let!(:first_method) { FactoryGirl.create(:payment_method,
|
|
547
|
-
|
|
543
|
+
let!(:first_method) { FactoryGirl.create(:payment_method, available_to_users: true,
|
|
544
|
+
available_to_admin: true) }
|
|
545
|
+
let!(:second_method) { FactoryGirl.create(:payment_method, available_to_users: true,
|
|
546
|
+
available_to_admin: true) }
|
|
548
547
|
|
|
549
548
|
before do
|
|
550
549
|
second_method.move_to_top
|
|
@@ -575,6 +574,23 @@ describe Spree::Order, type: :model do
|
|
|
575
574
|
[payment_method_with_store]
|
|
576
575
|
)
|
|
577
576
|
end
|
|
577
|
+
|
|
578
|
+
context 'and the store has an extra payment method unavailable to users' do
|
|
579
|
+
let!(:admin_only_payment_method) do create(:payment_method,
|
|
580
|
+
available_to_users: false,
|
|
581
|
+
available_to_admin: true)
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
before do
|
|
585
|
+
store_with_payment_methods.payment_methods << admin_only_payment_method
|
|
586
|
+
end
|
|
587
|
+
|
|
588
|
+
it 'returns only the payment methods available to users for that store' do
|
|
589
|
+
expect(order.available_payment_methods).to match_array(
|
|
590
|
+
[payment_method_with_store]
|
|
591
|
+
)
|
|
592
|
+
end
|
|
593
|
+
end
|
|
578
594
|
end
|
|
579
595
|
|
|
580
596
|
context 'when the store does not have payment methods' do
|
|
@@ -1488,56 +1504,4 @@ describe Spree::Order, type: :model do
|
|
|
1488
1504
|
end
|
|
1489
1505
|
end
|
|
1490
1506
|
end
|
|
1491
|
-
|
|
1492
|
-
describe "#validate_payments_attributes" do
|
|
1493
|
-
let(:attributes) { [ActionController::Parameters.new(payment_method_id: payment_method.id)] }
|
|
1494
|
-
subject do
|
|
1495
|
-
order.validate_payments_attributes(attributes)
|
|
1496
|
-
end
|
|
1497
|
-
|
|
1498
|
-
context "with empty array" do
|
|
1499
|
-
let(:attributes) { [] }
|
|
1500
|
-
it "doesn't error" do
|
|
1501
|
-
subject
|
|
1502
|
-
end
|
|
1503
|
-
end
|
|
1504
|
-
|
|
1505
|
-
context "with no payment method specified" do
|
|
1506
|
-
let(:attributes) { [ActionController::Parameters.new({})] }
|
|
1507
|
-
it "doesn't error" do
|
|
1508
|
-
subject
|
|
1509
|
-
end
|
|
1510
|
-
end
|
|
1511
|
-
|
|
1512
|
-
context "with valid payment method" do
|
|
1513
|
-
let(:payment_method) { create(:check_payment_method) }
|
|
1514
|
-
it "doesn't error" do
|
|
1515
|
-
subject
|
|
1516
|
-
end
|
|
1517
|
-
end
|
|
1518
|
-
|
|
1519
|
-
context "with inactive payment method" do
|
|
1520
|
-
let(:payment_method) { create(:check_payment_method, active: false) }
|
|
1521
|
-
|
|
1522
|
-
it "raises RecordNotFound" do
|
|
1523
|
-
expect { subject }.to raise_error(ActiveRecord::RecordNotFound)
|
|
1524
|
-
end
|
|
1525
|
-
end
|
|
1526
|
-
|
|
1527
|
-
context "with unavailable payment method" do
|
|
1528
|
-
let(:payment_method) { create(:check_payment_method, display_on: "back_end") }
|
|
1529
|
-
|
|
1530
|
-
it "raises RecordNotFound" do
|
|
1531
|
-
expect { subject }.to raise_error(ActiveRecord::RecordNotFound)
|
|
1532
|
-
end
|
|
1533
|
-
end
|
|
1534
|
-
|
|
1535
|
-
context "with soft-deleted payment method" do
|
|
1536
|
-
let(:payment_method) { create(:check_payment_method, deleted_at: Time.current) }
|
|
1537
|
-
|
|
1538
|
-
it "raises RecordNotFound" do
|
|
1539
|
-
expect { subject }.to raise_error(ActiveRecord::RecordNotFound)
|
|
1540
|
-
end
|
|
1541
|
-
end
|
|
1542
|
-
end
|
|
1543
1507
|
end
|
|
@@ -3,7 +3,6 @@ require 'spec_helper'
|
|
|
3
3
|
module Spree
|
|
4
4
|
RSpec.describe OrderUpdateAttributes do
|
|
5
5
|
let(:order) { create(:order) }
|
|
6
|
-
let(:payment_method) { create(:payment_method) }
|
|
7
6
|
let(:request_env) { nil }
|
|
8
7
|
let(:update) { described_class.new(order, attributes, request_env: request_env) }
|
|
9
8
|
|
|
@@ -26,10 +25,7 @@ module Spree
|
|
|
26
25
|
let(:attributes) do
|
|
27
26
|
{
|
|
28
27
|
payments_attributes: [
|
|
29
|
-
{
|
|
30
|
-
payment_method_id: payment_method.id,
|
|
31
|
-
source_attributes: attributes_for(:credit_card)
|
|
32
|
-
}
|
|
28
|
+
{ source_attributes: attributes_for(:credit_card) }
|
|
33
29
|
]
|
|
34
30
|
}
|
|
35
31
|
end
|
|
@@ -67,6 +67,257 @@ module Spree
|
|
|
67
67
|
end
|
|
68
68
|
end
|
|
69
69
|
|
|
70
|
+
describe '#recalculate_adjustments ' do
|
|
71
|
+
describe 'promotion recalculation' do
|
|
72
|
+
let(:order) { create(:order_with_line_items, line_items_count: 1, line_items_price: 10) }
|
|
73
|
+
let(:line_item) { order.line_items[0] }
|
|
74
|
+
|
|
75
|
+
context 'when the item quantity has changed' do
|
|
76
|
+
let(:promotion) { create(:promotion, promotion_actions: [promotion_action]) }
|
|
77
|
+
let(:promotion_action) { Spree::Promotion::Actions::CreateItemAdjustments.new(calculator: calculator) }
|
|
78
|
+
let(:calculator) { Spree::Calculator::FlatPercentItemTotal.new(preferred_flat_percent: 10) }
|
|
79
|
+
|
|
80
|
+
before do
|
|
81
|
+
promotion.activate(order: order)
|
|
82
|
+
order.update!
|
|
83
|
+
line_item.update!(quantity: 2)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it 'updates the promotion amount' do
|
|
87
|
+
expect {
|
|
88
|
+
order.update!
|
|
89
|
+
}.to change {
|
|
90
|
+
line_item.promo_total
|
|
91
|
+
}.from(-1).to(-2)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
context 'promotion chooser customization' do
|
|
96
|
+
before do
|
|
97
|
+
class Spree::TestPromotionChooser
|
|
98
|
+
def initialize(_adjustments)
|
|
99
|
+
raise 'Custom promotion chooser'
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
Spree::Config.promotion_chooser_class = Spree::TestPromotionChooser
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it 'uses the defined promotion chooser' do
|
|
107
|
+
expect { order.update! }.to raise_error('Custom promotion chooser')
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
context 'default promotion chooser (best promotion is always applied)' do
|
|
112
|
+
let(:calculator) { Calculator::FlatRate.new(preferred_amount: 10) }
|
|
113
|
+
|
|
114
|
+
let(:source) do
|
|
115
|
+
Promotion::Actions::CreateItemAdjustments.create!(
|
|
116
|
+
calculator: calculator,
|
|
117
|
+
promotion: promotion,
|
|
118
|
+
)
|
|
119
|
+
end
|
|
120
|
+
let(:promotion) { create(:promotion) }
|
|
121
|
+
|
|
122
|
+
def create_adjustment(label, amount)
|
|
123
|
+
create(
|
|
124
|
+
:adjustment,
|
|
125
|
+
order: order,
|
|
126
|
+
adjustable: line_item,
|
|
127
|
+
source: source,
|
|
128
|
+
amount: amount,
|
|
129
|
+
finalized: true,
|
|
130
|
+
label: label,
|
|
131
|
+
)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it 'should make all but the most valuable promotion adjustment ineligible, leaving non promotion adjustments alone' do
|
|
135
|
+
create_adjustment('Promotion A', -100)
|
|
136
|
+
create_adjustment('Promotion B', -200)
|
|
137
|
+
create_adjustment('Promotion C', -300)
|
|
138
|
+
create(:adjustment, order: order,
|
|
139
|
+
adjustable: line_item,
|
|
140
|
+
source: nil,
|
|
141
|
+
amount: -500,
|
|
142
|
+
finalized: true,
|
|
143
|
+
label: 'Some other credit')
|
|
144
|
+
line_item.adjustments.each { |a| a.update_column(:eligible, true) }
|
|
145
|
+
|
|
146
|
+
order.update!
|
|
147
|
+
|
|
148
|
+
expect(line_item.adjustments.promotion.eligible.count).to eq(1)
|
|
149
|
+
expect(line_item.adjustments.promotion.eligible.first.label).to eq('Promotion C')
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
it 'should choose the most recent promotion adjustment when amounts are equal' do
|
|
153
|
+
# Using Timecop is a regression test
|
|
154
|
+
Timecop.freeze do
|
|
155
|
+
create_adjustment('Promotion A', -200)
|
|
156
|
+
create_adjustment('Promotion B', -200)
|
|
157
|
+
end
|
|
158
|
+
line_item.adjustments.each { |a| a.update_column(:eligible, true) }
|
|
159
|
+
|
|
160
|
+
order.update!
|
|
161
|
+
|
|
162
|
+
expect(line_item.adjustments.promotion.eligible.count).to eq(1)
|
|
163
|
+
expect(line_item.adjustments.promotion.eligible.first.label).to eq('Promotion B')
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
it 'should choose the most recent promotion adjustment when amounts are equal' do
|
|
167
|
+
# Using Timecop is a regression test
|
|
168
|
+
Timecop.freeze do
|
|
169
|
+
create_adjustment('Promotion A', -200)
|
|
170
|
+
create_adjustment('Promotion B', -200)
|
|
171
|
+
end
|
|
172
|
+
line_item.adjustments.each { |a| a.update_column(:eligible, true) }
|
|
173
|
+
|
|
174
|
+
order.update!
|
|
175
|
+
|
|
176
|
+
expect(line_item.adjustments.promotion.eligible.count).to eq(1)
|
|
177
|
+
expect(line_item.adjustments.promotion.eligible.first.label).to eq('Promotion B')
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
context 'when previously ineligible promotions become available' do
|
|
181
|
+
let(:order_promo1) { create(:promotion, :with_order_adjustment, :with_item_total_rule, weighted_order_adjustment_amount: 5, item_total_threshold_amount: 10) }
|
|
182
|
+
let(:order_promo2) { create(:promotion, :with_order_adjustment, :with_item_total_rule, weighted_order_adjustment_amount: 10, item_total_threshold_amount: 20) }
|
|
183
|
+
let(:order_promos) { [order_promo1, order_promo2] }
|
|
184
|
+
let(:line_item_promo1) { create(:promotion, :with_line_item_adjustment, :with_item_total_rule, adjustment_rate: 2.5, item_total_threshold_amount: 10, apply_automatically: true) }
|
|
185
|
+
let(:line_item_promo2) { create(:promotion, :with_line_item_adjustment, :with_item_total_rule, adjustment_rate: 5, item_total_threshold_amount: 20, apply_automatically: true) }
|
|
186
|
+
let(:line_item_promos) { [line_item_promo1, line_item_promo2] }
|
|
187
|
+
let(:order) { create(:order_with_line_items, line_items_count: 1) }
|
|
188
|
+
|
|
189
|
+
# Apply promotions in different sequences. Results should be the same.
|
|
190
|
+
promo_sequences = [
|
|
191
|
+
[0, 1],
|
|
192
|
+
[1, 0],
|
|
193
|
+
]
|
|
194
|
+
|
|
195
|
+
promo_sequences.each do |promo_sequence|
|
|
196
|
+
context "with promo sequence #{promo_sequence}" do
|
|
197
|
+
it 'should pick the best order-level promo according to current eligibility' do
|
|
198
|
+
# apply both promos to the order, even though only promo1 is eligible
|
|
199
|
+
order_promos[promo_sequence[0]].activate order: order
|
|
200
|
+
order_promos[promo_sequence[1]].activate order: order
|
|
201
|
+
|
|
202
|
+
order.update!
|
|
203
|
+
order.reload
|
|
204
|
+
expect(order.all_adjustments.count).to eq(2), 'Expected two adjustments'
|
|
205
|
+
expect(order.all_adjustments.eligible.count).to eq(1), 'Expected one elegible adjustment'
|
|
206
|
+
expect(order.all_adjustments.eligible.first.source.promotion).to eq(order_promo1), 'Expected promo1 to be used'
|
|
207
|
+
|
|
208
|
+
order.contents.add create(:variant, price: 10), 1
|
|
209
|
+
order.save
|
|
210
|
+
|
|
211
|
+
order.reload
|
|
212
|
+
expect(order.all_adjustments.count).to eq(2), 'Expected two adjustments'
|
|
213
|
+
expect(order.all_adjustments.eligible.count).to eq(1), 'Expected one elegible adjustment'
|
|
214
|
+
expect(order.all_adjustments.eligible.first.source.promotion).to eq(order_promo2), 'Expected promo2 to be used'
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
it 'should pick the best line-item-level promo according to current eligibility' do
|
|
218
|
+
# apply both promos to the order, even though only promo1 is eligible
|
|
219
|
+
line_item_promos[promo_sequence[0]].activate order: order
|
|
220
|
+
line_item_promos[promo_sequence[1]].activate order: order
|
|
221
|
+
|
|
222
|
+
order.reload
|
|
223
|
+
expect(order.all_adjustments.count).to eq(1), 'Expected one adjustment'
|
|
224
|
+
expect(order.all_adjustments.eligible.count).to eq(1), 'Expected one elegible adjustment'
|
|
225
|
+
# line_item_promo1 is the only one that has thus far met the order total threshold, it is the only promo which should be applied.
|
|
226
|
+
expect(order.all_adjustments.first.source.promotion).to eq(line_item_promo1), 'Expected line_item_promo1 to be used'
|
|
227
|
+
|
|
228
|
+
order.contents.add create(:variant, price: 10), 1
|
|
229
|
+
order.save
|
|
230
|
+
|
|
231
|
+
order.reload
|
|
232
|
+
expect(order.all_adjustments.count).to eq(4), 'Expected four adjustments'
|
|
233
|
+
expect(order.all_adjustments.eligible.count).to eq(2), 'Expected two elegible adjustments'
|
|
234
|
+
order.all_adjustments.eligible.each do |adjustment|
|
|
235
|
+
expect(adjustment.source.promotion).to eq(line_item_promo2), 'Expected line_item_promo2 to be used'
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
context 'multiple adjustments and the best one is not eligible' do
|
|
243
|
+
let!(:promo_a) { create_adjustment('Promotion A', -100) }
|
|
244
|
+
let!(:promo_c) { create_adjustment('Promotion C', -300) }
|
|
245
|
+
|
|
246
|
+
before do
|
|
247
|
+
promo_a.update_column(:eligible, true)
|
|
248
|
+
promo_c.update_column(:eligible, false)
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# regression for https://github.com/spree/spree/issues/3274
|
|
252
|
+
it 'still makes the previous best eligible adjustment valid' do
|
|
253
|
+
order.update!
|
|
254
|
+
expect(line_item.adjustments.promotion.eligible.first.label).to eq('Promotion A')
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
it 'should only leave one adjustment even if 2 have the same amount' do
|
|
259
|
+
create_adjustment('Promotion A', -100)
|
|
260
|
+
create_adjustment('Promotion B', -200)
|
|
261
|
+
create_adjustment('Promotion C', -200)
|
|
262
|
+
|
|
263
|
+
order.update!
|
|
264
|
+
|
|
265
|
+
expect(line_item.adjustments.promotion.eligible.count).to eq(1)
|
|
266
|
+
expect(line_item.adjustments.promotion.eligible.first.amount.to_i).to eq(-200)
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
describe 'tax recalculation' do
|
|
272
|
+
let!(:ship_address) { create(:address) }
|
|
273
|
+
let!(:tax_zone) { create(:global_zone) } # will include the above address
|
|
274
|
+
let!(:tax_rate) { create(:tax_rate, zone: tax_zone, tax_category: tax_category) }
|
|
275
|
+
|
|
276
|
+
let(:order) do
|
|
277
|
+
create(
|
|
278
|
+
:order_with_line_items,
|
|
279
|
+
line_items_attributes: [{ price: 10, variant: variant }],
|
|
280
|
+
ship_address: ship_address,
|
|
281
|
+
)
|
|
282
|
+
end
|
|
283
|
+
let(:line_item) { order.line_items[0] }
|
|
284
|
+
|
|
285
|
+
let(:variant) { create(:variant, tax_category: tax_category) }
|
|
286
|
+
let(:tax_category) { create(:tax_category) }
|
|
287
|
+
|
|
288
|
+
context 'when the item quantity has changed' do
|
|
289
|
+
before do
|
|
290
|
+
line_item.update!(quantity: 2)
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
it 'updates the promotion amount' do
|
|
294
|
+
expect {
|
|
295
|
+
order.update!
|
|
296
|
+
}.to change {
|
|
297
|
+
line_item.additional_tax_total
|
|
298
|
+
}.from(1).to(2)
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
context 'with a custom tax_adjuster_class' do
|
|
303
|
+
let(:custom_adjuster_class) { double }
|
|
304
|
+
let(:custom_adjuster_instance) { double }
|
|
305
|
+
|
|
306
|
+
before do
|
|
307
|
+
order # generate this first so we can expect it
|
|
308
|
+
Spree::Config.tax_adjuster_class = custom_adjuster_class
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
it 'uses the configured class' do
|
|
312
|
+
expect(custom_adjuster_class).to receive(:new).with(order).at_least(:once).and_return(custom_adjuster_instance)
|
|
313
|
+
expect(custom_adjuster_instance).to receive(:adjust!).at_least(:once)
|
|
314
|
+
|
|
315
|
+
order.update!
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
|
|
70
321
|
context "updating shipment state" do
|
|
71
322
|
before do
|
|
72
323
|
allow(order).to receive_messages backordered?: false
|