solidus_core 2.1.1 → 2.2.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/Rakefile +0 -1
- data/app/assets/config/solidus_core_manifest.js +1 -0
- data/app/assets/javascripts/spree.js.erb +72 -0
- data/app/helpers/spree/store_helper.rb +5 -0
- data/app/jobs/spree/promotion_code_batch_job.rb +24 -0
- data/app/mailers/spree/promotion_code_batch_mailer.rb +13 -0
- data/app/models/concerns/spree/calculated_adjustments.rb +1 -1
- data/app/models/concerns/spree/ordered_property_value_list.rb +2 -2
- data/app/models/concerns/spree/user_address_book.rb +4 -4
- data/app/models/concerns/spree/user_methods.rb +7 -0
- data/app/models/concerns/spree/user_payment_source.rb +12 -5
- data/app/models/spree/address.rb +14 -3
- data/app/models/spree/adjustment.rb +13 -1
- data/app/models/spree/app_configuration.rb +0 -19
- data/app/models/spree/base.rb +2 -0
- data/app/models/spree/credit_card.rb +34 -43
- data/app/models/spree/gateway/bogus.rb +1 -1
- data/app/models/spree/gateway.rb +6 -4
- data/app/models/spree/inventory_unit.rb +3 -2
- data/app/models/spree/order/checkout.rb +187 -273
- data/app/models/spree/order.rb +137 -71
- data/app/models/spree/order_contents.rb +1 -1
- data/app/models/spree/order_inventory.rb +11 -11
- data/app/models/spree/order_promotion.rb +2 -0
- data/app/models/spree/order_update_attributes.rb +1 -8
- data/app/models/spree/order_updater.rb +67 -63
- data/app/models/spree/payment.rb +0 -1
- data/app/models/spree/payment_create.rb +27 -7
- data/app/models/spree/payment_method/store_credit.rb +3 -3
- data/app/models/spree/payment_method.rb +4 -1
- data/app/models/spree/payment_source.rb +45 -0
- data/app/models/spree/product/scopes.rb +24 -24
- data/app/models/spree/product.rb +4 -4
- data/app/models/spree/promotion.rb +2 -0
- data/app/models/spree/promotion_code/batch_builder.rb +63 -0
- data/app/models/spree/promotion_code.rb +1 -0
- data/app/models/spree/promotion_code_batch.rb +25 -0
- data/app/models/spree/promotion_handler/cart.rb +2 -2
- data/app/models/spree/promotion_handler/coupon.rb +1 -2
- data/app/models/spree/promotion_handler/free_shipping.rb +32 -21
- data/app/models/spree/promotion_handler/page.rb +1 -1
- data/app/models/spree/reimbursement.rb +1 -1
- data/app/models/spree/return_authorization.rb +0 -28
- data/app/models/spree/return_item.rb +1 -1
- data/app/models/spree/shipment.rb +4 -4
- data/app/models/spree/shipping_method.rb +2 -2
- data/app/models/spree/shipping_rate.rb +1 -1
- data/app/models/spree/stock/availability_validator.rb +16 -17
- data/app/models/spree/stock/coordinator.rb +3 -3
- data/app/models/spree/stock/package.rb +1 -1
- data/app/models/spree/stock/quantifier.rb +5 -4
- data/app/models/spree/stock_location.rb +2 -2
- data/app/models/spree/store.rb +2 -2
- data/app/models/spree/store_credit.rb +1 -1
- data/app/models/spree/tax/tax_helpers.rb +3 -3
- data/app/models/spree/tax_rate.rb +7 -1
- data/app/models/spree/taxonomy.rb +1 -1
- data/app/models/spree/variant/scopes.rb +5 -5
- data/app/models/spree/variant/vat_price_generator.rb +8 -5
- data/app/models/spree/variant.rb +1 -0
- data/app/models/spree/wallet/add_payment_sources_to_wallet.rb +19 -10
- data/app/models/spree/wallet/default_payment_builder.rb +6 -6
- data/app/models/spree/wallet.rb +71 -0
- data/app/models/spree/wallet_payment_source.rb +17 -0
- data/app/models/spree/zone.rb +1 -1
- data/app/views/spree/carton_mailer/shipped_email.text.erb +1 -1
- data/app/views/spree/promotion_code_batch_mailer/promotion_code_batch_errored.text.erb +2 -0
- data/app/views/spree/promotion_code_batch_mailer/promotion_code_batch_finished.text.erb +2 -0
- data/app/views/spree/reimbursement_mailer/reimbursement_email.html.erb +0 -7
- data/app/views/spree/reimbursement_mailer/reimbursement_email.text.erb +0 -5
- data/app/views/spree/shared/_error_messages.html.erb +1 -1
- data/app/views/spree/shipment_mailer/shipped_email.html.erb +1 -1
- data/config/initializers/assets.rb +1 -1
- data/config/initializers/friendly_id.rb +1 -1
- data/config/locales/en.yml +50 -12
- data/db/default/spree/store_credit.rb +2 -1
- data/db/migrate/20130826062534_add_depth_to_spree_taxons.rb +4 -6
- data/db/migrate/20160420044191_create_spree_wallet_payment_sources.rb +23 -0
- data/db/migrate/20160420181916_migrate_credit_cards_to_wallet_payment_sources.rb +26 -0
- data/db/migrate/20161017102621_create_spree_promotion_code_batch.rb +36 -0
- data/db/migrate/20161129035810_add_index_to_spree_payments_number.rb +5 -0
- data/db/migrate/20170223235001_remove_spree_store_credits_column.rb +5 -0
- data/lib/generators/spree/dummy/templates/rails/application.rb +1 -1
- data/lib/generators/spree/dummy/templates/rails/test.rb +1 -1
- data/lib/generators/spree/install/install_generator.rb +6 -5
- data/lib/spree/core/controller_helpers/payment_parameters.rb +54 -0
- data/lib/spree/core/engine.rb +6 -9
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/core.rb +0 -1
- data/lib/spree/money.rb +18 -0
- data/lib/spree/permission_sets/default_customer.rb +1 -1
- data/lib/spree/permitted_attributes.rb +1 -1
- data/lib/spree/testing_support/authorization_helpers.rb +1 -0
- data/lib/spree/testing_support/capybara_ext.rb +13 -0
- data/lib/spree/testing_support/factories/order_factory.rb +5 -1
- data/lib/spree/testing_support/factories/payment_factory.rb +1 -1
- data/lib/spree/testing_support/factories/shipment_factory.rb +0 -1
- data/solidus_core.gemspec +3 -3
- data/spec/jobs/promotion_code_batch_job_spec.rb +65 -0
- data/spec/lib/calculated_adjustments_spec.rb +105 -1
- data/spec/lib/spree/core/testing_support/factories/order_factory_spec.rb +4 -1
- data/spec/lib/spree/core/testing_support/factories/payment_factory_spec.rb +8 -0
- data/spec/lib/spree/money_spec.rb +32 -0
- data/spec/lib/spree/permission_sets/default_customer_spec.rb +20 -0
- data/spec/mailers/promotion_code_batch_mailer_spec.rb +45 -0
- data/spec/models/spree/credit_card_spec.rb +86 -86
- data/spec/models/spree/gateway_spec.rb +3 -1
- data/spec/models/spree/inventory_unit_spec.rb +12 -4
- data/spec/models/spree/order/checkout_spec.rb +11 -32
- data/spec/models/spree/order/tax_spec.rb +2 -2
- data/spec/models/spree/order_contents_spec.rb +24 -1
- data/spec/models/spree/order_inventory_spec.rb +130 -83
- data/spec/models/spree/order_spec.rb +15 -117
- data/spec/models/spree/order_update_attributes_spec.rb +1 -44
- data/spec/models/spree/order_updater_spec.rb +10 -13
- data/spec/models/spree/payment_create_spec.rb +5 -1
- data/spec/models/spree/payment_method_spec.rb +16 -0
- data/spec/models/spree/payment_spec.rb +14 -8
- data/spec/models/spree/promotion_code/batch_builder_spec.rb +61 -0
- data/spec/models/spree/promotion_code_batch_spec.rb +58 -0
- data/spec/models/spree/promotion_code_spec.rb +4 -0
- data/spec/models/spree/promotion_spec.rb +3 -6
- data/spec/models/spree/return_authorization_spec.rb +0 -59
- data/spec/models/spree/shipment_spec.rb +4 -4
- data/spec/models/spree/stock/availability_validator_spec.rb +64 -9
- data/spec/models/spree/tax/item_adjuster_spec.rb +1 -2
- data/spec/models/spree/unit_cancel_spec.rb +0 -85
- data/spec/models/spree/user_spec.rb +3 -1
- data/spec/models/spree/variant/vat_price_generator_spec.rb +8 -2
- data/spec/models/spree/variant_spec.rb +16 -4
- data/spec/models/spree/wallet_payment_source_spec.rb +46 -0
- data/spec/models/spree/wallet_spec.rb +128 -0
- data/spec/support/concerns/payment_source.rb +64 -0
- metadata +51 -25
- data/app/assets/javascripts/spree.js.coffee.erb +0 -64
- data/app/models/spree/promotion_builder.rb +0 -55
- data/app/models/spree/promotion_code/code_builder.rb +0 -62
- data/config/initializers/premailer_assets.rb +0 -1
- data/lib/spree/core/unreturned_item_charger.rb +0 -106
- data/lib/tasks/exchanges.rake +0 -47
- data/spec/lib/spree/core/unreturned_item_charger_spec.rb +0 -126
- data/spec/lib/tasks/exchanges_spec.rb +0 -220
- data/spec/models/spree/promotion_builder_spec.rb +0 -120
- data/spec/models/spree/promotion_code/code_builder_spec.rb +0 -77
|
@@ -67,6 +67,22 @@ describe Spree::PaymentMethod, type: :model do
|
|
|
67
67
|
|
|
68
68
|
it { is_expected.to contain_exactly(payment_method_back_display, payment_method_both_display, payment_method_nil_display)}
|
|
69
69
|
end
|
|
70
|
+
|
|
71
|
+
context "when searching for payment methods available to a store" do
|
|
72
|
+
subject { Spree::PaymentMethod.available_to_store(store) }
|
|
73
|
+
|
|
74
|
+
context "when the store is nil" do
|
|
75
|
+
let(:store) { nil }
|
|
76
|
+
it "raises an argument error" do
|
|
77
|
+
expect { subject }.to raise_error(ArgumentError, "You must provide a store")
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
context "when the store exists" do
|
|
82
|
+
let(:store) { create(:store, payment_methods: [payment_method_back_display]) }
|
|
83
|
+
it { is_expected.to contain_exactly(payment_method_back_display) }
|
|
84
|
+
end
|
|
85
|
+
end
|
|
70
86
|
end
|
|
71
87
|
|
|
72
88
|
describe ".available" do
|
|
@@ -653,13 +653,12 @@ describe Spree::Payment, type: :model do
|
|
|
653
653
|
end
|
|
654
654
|
|
|
655
655
|
context "completed orders" do
|
|
656
|
-
let(:payment_method) { create(:check_payment_method) }
|
|
657
656
|
before { allow(order).to receive_messages completed?: true }
|
|
658
657
|
|
|
659
658
|
it "updates payment_state and shipments" do
|
|
660
659
|
expect(order.updater).to receive(:update_payment_state)
|
|
661
660
|
expect(order.updater).to receive(:update_shipment_state)
|
|
662
|
-
Spree::Payment.create
|
|
661
|
+
Spree::Payment.create(amount: 100, order: order)
|
|
663
662
|
end
|
|
664
663
|
end
|
|
665
664
|
|
|
@@ -743,13 +742,12 @@ describe Spree::Payment, type: :model do
|
|
|
743
742
|
end
|
|
744
743
|
|
|
745
744
|
describe "invalidating payments updates in memory objects" do
|
|
746
|
-
let(:payment_method) { create(:check_payment_method) }
|
|
747
745
|
before do
|
|
748
|
-
Spree::PaymentCreate.new(order, amount: 1
|
|
746
|
+
Spree::PaymentCreate.new(order, amount: 1).build.save!
|
|
749
747
|
expect(order.payments.map(&:state)).to contain_exactly(
|
|
750
748
|
'checkout'
|
|
751
749
|
)
|
|
752
|
-
Spree::PaymentCreate.new(order, amount: 2
|
|
750
|
+
Spree::PaymentCreate.new(order, amount: 2).build.save!
|
|
753
751
|
end
|
|
754
752
|
|
|
755
753
|
it 'should not have stale payments' do
|
|
@@ -808,11 +806,12 @@ describe Spree::Payment, type: :model do
|
|
|
808
806
|
let(:order) { create(:order, user: user) }
|
|
809
807
|
let(:user) { create(:user) }
|
|
810
808
|
let!(:credit_card) { create(:credit_card, user_id: order.user_id) }
|
|
809
|
+
let!(:wallet_payment_source) { user.wallet.add(credit_card) }
|
|
811
810
|
|
|
812
811
|
let(:params) do
|
|
813
812
|
{
|
|
814
813
|
source_attributes: {
|
|
815
|
-
|
|
814
|
+
wallet_payment_source_id: wallet_payment_source.id,
|
|
816
815
|
verification_value: '321'
|
|
817
816
|
}
|
|
818
817
|
}
|
|
@@ -849,14 +848,21 @@ describe Spree::Payment, type: :model do
|
|
|
849
848
|
|
|
850
849
|
context 'the credit card belongs to a different user' do
|
|
851
850
|
let(:other_user) { create(:user) }
|
|
852
|
-
before
|
|
851
|
+
before do
|
|
852
|
+
credit_card.update!(user_id: other_user.id)
|
|
853
|
+
user.wallet.remove(credit_card)
|
|
854
|
+
other_user.wallet.add(credit_card)
|
|
855
|
+
end
|
|
853
856
|
it 'errors' do
|
|
854
857
|
expect { subject }.to raise_error(ActiveRecord::RecordNotFound)
|
|
855
858
|
end
|
|
856
859
|
end
|
|
857
860
|
|
|
858
861
|
context 'the credit card has no user' do
|
|
859
|
-
before
|
|
862
|
+
before do
|
|
863
|
+
credit_card.update!(user_id: nil)
|
|
864
|
+
user.wallet.remove(credit_card)
|
|
865
|
+
end
|
|
860
866
|
it 'errors' do
|
|
861
867
|
expect { subject }.to raise_error(ActiveRecord::RecordNotFound)
|
|
862
868
|
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe Spree::PromotionCode::BatchBuilder do
|
|
4
|
+
let(:promotion) { create(:promotion) }
|
|
5
|
+
let(:base_code) { "abc" }
|
|
6
|
+
let(:promotion_code_batch) do
|
|
7
|
+
Spree::PromotionCodeBatch.create!(
|
|
8
|
+
promotion_id: promotion.id,
|
|
9
|
+
base_code: base_code,
|
|
10
|
+
number_of_codes: 10,
|
|
11
|
+
email: "test@email.com"
|
|
12
|
+
)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
subject { described_class.new promotion_code_batch }
|
|
16
|
+
|
|
17
|
+
describe "#build_promotion_codes" do
|
|
18
|
+
context "with a failed build" do
|
|
19
|
+
before do
|
|
20
|
+
allow(subject).to receive(:generate_random_codes).and_raise "Error"
|
|
21
|
+
|
|
22
|
+
expect { subject.build_promotion_codes }.to raise_error RuntimeError
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "updates the error and state on promotion batch" do
|
|
26
|
+
expect(promotion_code_batch.reload.error).to eq("#<RuntimeError: Error>")
|
|
27
|
+
expect(promotion_code_batch.reload.state).to eq("failed")
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
context "with a successful build" do
|
|
31
|
+
before do
|
|
32
|
+
allow(Spree::PromotionCodeBatchMailer)
|
|
33
|
+
.to receive(:promotion_code_batch_finished)
|
|
34
|
+
.and_call_original
|
|
35
|
+
|
|
36
|
+
subject.build_promotion_codes
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "update the promotion codes count for the batch" do
|
|
40
|
+
expect(promotion_code_batch.promotion_codes.count).to eq(10)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "builds the correct number of codes" do
|
|
44
|
+
expect(subject.promotion.codes.size).to eq(10)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "builds codes with distinct values" do
|
|
48
|
+
expect(subject.promotion.codes.map(&:value).uniq.size).to eq(10)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "builds codes with the same base prefix" do
|
|
52
|
+
values = subject.promotion.codes.map(&:value)
|
|
53
|
+
expect(values.all? { |val| val.starts_with?("#{base_code}_") }).to be true
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "updates the promotion code batch state to completed" do
|
|
57
|
+
expect(promotion_code_batch.state).to eq("completed")
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe Spree::PromotionCodeBatch, type: :model do
|
|
4
|
+
include ActiveJob::TestHelper
|
|
5
|
+
|
|
6
|
+
subject do
|
|
7
|
+
described_class.create!(
|
|
8
|
+
promotion_id: create(:promotion).id,
|
|
9
|
+
base_code: "abc",
|
|
10
|
+
number_of_codes: 1,
|
|
11
|
+
error: nil,
|
|
12
|
+
email: "test@email.com"
|
|
13
|
+
)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe "#process" do
|
|
17
|
+
context "with a pending code batch" do
|
|
18
|
+
it "should call the worker" do
|
|
19
|
+
ActiveJob::Base.queue_adapter = :test
|
|
20
|
+
|
|
21
|
+
expect { subject.process }
|
|
22
|
+
.to have_enqueued_job(Spree::PromotionCodeBatchJob)
|
|
23
|
+
|
|
24
|
+
clear_enqueued_jobs
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "should update the state to processing" do
|
|
28
|
+
subject.process
|
|
29
|
+
|
|
30
|
+
expect(subject.state).to eq("processing")
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context "with a processing batch" do
|
|
35
|
+
before { subject.update_attribute(:state, "processing") }
|
|
36
|
+
|
|
37
|
+
it "should raise an error" do
|
|
38
|
+
expect{ subject.process }.to raise_error Spree::PromotionCodeBatch::CantProcessStartedBatch
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
context "with a completed batch" do
|
|
43
|
+
before { subject.update_attribute(:state, "completed") }
|
|
44
|
+
|
|
45
|
+
it "should raise an error" do
|
|
46
|
+
expect{ subject.process }.to raise_error Spree::PromotionCodeBatch::CantProcessStartedBatch
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
context "with a failed batch" do
|
|
51
|
+
before { subject.update_attribute(:state, "failed") }
|
|
52
|
+
|
|
53
|
+
it "should raise an error" do
|
|
54
|
+
expect{ subject.process }.to raise_error Spree::PromotionCodeBatch::CantProcessStartedBatch
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -164,21 +164,25 @@ RSpec.describe Spree::PromotionCode do
|
|
|
164
164
|
order.complete!
|
|
165
165
|
end
|
|
166
166
|
end
|
|
167
|
+
|
|
167
168
|
it "makes the promotion ineligible" do
|
|
168
169
|
expect{
|
|
169
170
|
order.complete
|
|
170
171
|
}.to change{ promo_adjustment.reload.eligible }.to(false)
|
|
171
172
|
end
|
|
173
|
+
|
|
172
174
|
it "adjusts the promo_total" do
|
|
173
175
|
expect{
|
|
174
176
|
order.complete
|
|
175
177
|
}.to change(order, :promo_total).by(10)
|
|
176
178
|
end
|
|
179
|
+
|
|
177
180
|
it "increases the total to remove the promo" do
|
|
178
181
|
expect{
|
|
179
182
|
order.complete
|
|
180
183
|
}.to change(order, :total).from(30).to(40)
|
|
181
184
|
end
|
|
185
|
+
|
|
182
186
|
it "resets the state of the order" do
|
|
183
187
|
expect{
|
|
184
188
|
order.complete
|
|
@@ -597,8 +597,7 @@ describe Spree::Promotion, type: :model do
|
|
|
597
597
|
allow(rule2).to receive_messages(eligible?: true, applicable?: true)
|
|
598
598
|
|
|
599
599
|
promotion.promotion_rules = [rule1, rule2]
|
|
600
|
-
allow(promotion).to
|
|
601
|
-
allow(promotion).to receive_message_chain(:rules, :for).and_return(promotion.promotion_rules)
|
|
600
|
+
allow(promotion.promotion_rules).to receive(:for).and_return(promotion.promotion_rules)
|
|
602
601
|
end
|
|
603
602
|
it "returns the eligible rules" do
|
|
604
603
|
expect(promotion.eligible_rules(promotable)).to eq [rule1, rule2]
|
|
@@ -616,8 +615,7 @@ describe Spree::Promotion, type: :model do
|
|
|
616
615
|
allow(rule2).to receive_messages(eligible?: false, applicable?: true, eligibility_errors: errors)
|
|
617
616
|
|
|
618
617
|
promotion.promotion_rules = [rule1, rule2]
|
|
619
|
-
allow(promotion).to
|
|
620
|
-
allow(promotion).to receive_message_chain(:rules, :for).and_return(promotion.promotion_rules)
|
|
618
|
+
allow(promotion.promotion_rules).to receive(:for).and_return(promotion.promotion_rules)
|
|
621
619
|
end
|
|
622
620
|
it "returns nil" do
|
|
623
621
|
expect(promotion.eligible_rules(promotable)).to be_nil
|
|
@@ -649,8 +647,7 @@ describe Spree::Promotion, type: :model do
|
|
|
649
647
|
allow(rule).to receive_messages(eligible?: false, applicable?: true, eligibility_errors: errors)
|
|
650
648
|
|
|
651
649
|
promotion.promotion_rules = [rule]
|
|
652
|
-
allow(promotion).to
|
|
653
|
-
allow(promotion).to receive_message_chain(:rules, :none?).and_return(false)
|
|
650
|
+
allow(promotion.promotion_rules).to receive(:for).and_return(promotion.promotion_rules)
|
|
654
651
|
end
|
|
655
652
|
it "returns nil" do
|
|
656
653
|
expect(promotion.eligible_rules(promotable)).to be_nil
|
|
@@ -44,65 +44,6 @@ describe Spree::ReturnAuthorization, type: :model do
|
|
|
44
44
|
expect(return_authorization.errors['base'].size).to eq 0
|
|
45
45
|
end
|
|
46
46
|
end
|
|
47
|
-
|
|
48
|
-
context "expedited exchanges are configured" do
|
|
49
|
-
let(:order) { create(:shipped_order, line_items_count: 2) }
|
|
50
|
-
let(:exchange_return_item) { build(:exchange_return_item, inventory_unit: order.inventory_units.first) }
|
|
51
|
-
let(:return_item) { build(:return_item, inventory_unit: order.inventory_units.last) }
|
|
52
|
-
subject { create(:return_authorization, order: order, return_items: [exchange_return_item, return_item]) }
|
|
53
|
-
|
|
54
|
-
before do
|
|
55
|
-
Spree::Config[:expedited_exchanges] = true
|
|
56
|
-
@pre_exchange_hooks = subject.class.pre_expedited_exchange_hooks
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
after do
|
|
60
|
-
subject.class.pre_expedited_exchange_hooks = @pre_exchange_hooks
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
context "no items to exchange" do
|
|
64
|
-
subject { create(:return_authorization, order: order) }
|
|
65
|
-
|
|
66
|
-
it "does not create a reimbursement" do
|
|
67
|
-
expect{ subject.save }.to_not change { Spree::Reimbursement.count }
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
context "items to exchange" do
|
|
72
|
-
it "calls pre_expedited_exchange hooks with the return items to exchange" do
|
|
73
|
-
hook = double(:as_null_object)
|
|
74
|
-
expect(hook).to receive(:call).with [exchange_return_item]
|
|
75
|
-
subject.class.pre_expedited_exchange_hooks = [hook]
|
|
76
|
-
subject.save
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
it "attempts to accept all return items requiring exchange" do
|
|
80
|
-
expect(exchange_return_item).to receive :attempt_accept
|
|
81
|
-
expect(return_item).not_to receive :attempt_accept
|
|
82
|
-
subject.save
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
it "performs an exchange reimbursement for the exchange return items" do
|
|
86
|
-
subject.save
|
|
87
|
-
reimbursement = Spree::Reimbursement.last
|
|
88
|
-
expect(reimbursement.order).to eq subject.order
|
|
89
|
-
expect(reimbursement.return_items).to eq [exchange_return_item]
|
|
90
|
-
expect(exchange_return_item.reload.exchange_shipment).to be_present
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
context "the reimbursement fails" do
|
|
94
|
-
before do
|
|
95
|
-
allow_any_instance_of(Spree::Reimbursement).to receive(:save) { false }
|
|
96
|
-
allow_any_instance_of(Spree::Reimbursement).to receive(:errors) { double(full_messages: "foo") }
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
it "puts errors on the return authorization" do
|
|
100
|
-
subject.save
|
|
101
|
-
expect(subject.errors[:base]).to include "foo"
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
end
|
|
106
47
|
end
|
|
107
48
|
|
|
108
49
|
describe ".before_create" do
|
|
@@ -724,11 +724,10 @@ describe Spree::Shipment, type: :model do
|
|
|
724
724
|
expect { shipment.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
725
725
|
end
|
|
726
726
|
|
|
727
|
-
it "
|
|
727
|
+
it "can be destroyed when ready" do
|
|
728
728
|
shipment = create(:shipment, state: "ready")
|
|
729
|
-
expect(shipment.destroy).to
|
|
730
|
-
expect
|
|
731
|
-
expect { shipment.reload }.not_to raise_error
|
|
729
|
+
expect(shipment.destroy).to be_truthy
|
|
730
|
+
expect { shipment.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
732
731
|
end
|
|
733
732
|
|
|
734
733
|
it "cannot be destroyed when shipped" do
|
|
@@ -753,6 +752,7 @@ describe Spree::Shipment, type: :model do
|
|
|
753
752
|
before do
|
|
754
753
|
stock_item.set_count_on_hand(10)
|
|
755
754
|
stock_item.update_attributes!(backorderable: false)
|
|
755
|
+
inventory_unit.update_attributes!(pending: true)
|
|
756
756
|
end
|
|
757
757
|
|
|
758
758
|
subject { shipment.finalize! }
|
|
@@ -26,6 +26,7 @@ module Spree
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
it "doesn't add a validation error" do
|
|
29
|
+
subject
|
|
29
30
|
expect(line_item.errors).to be_empty
|
|
30
31
|
end
|
|
31
32
|
end
|
|
@@ -53,28 +54,82 @@ module Spree
|
|
|
53
54
|
context "line_item is part of a shipment" do
|
|
54
55
|
let!(:order) { create(:order_with_line_items) }
|
|
55
56
|
|
|
56
|
-
context "has stock in
|
|
57
|
+
context "has stock in one stock location" do
|
|
57
58
|
let(:line_item) { order.line_items.first }
|
|
58
59
|
|
|
59
60
|
before do
|
|
60
|
-
|
|
61
|
-
Spree::StockItem.where(variant_id: variant_ids).update_all(count_on_hand: 10, backorderable: false)
|
|
61
|
+
line_item.variant.stock_items.update_all(count_on_hand: 10, backorderable: false)
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
include_examples "passes validation"
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
-
context "
|
|
68
|
-
let(:
|
|
69
|
-
let(:
|
|
67
|
+
context "with stock in multiple locations" do
|
|
68
|
+
let(:line_item) { order.line_items.first }
|
|
69
|
+
let(:variant) { line_item.variant }
|
|
70
70
|
let!(:stock_location_1) { create(:stock_location, name: "Test Warehouse", active: false) }
|
|
71
71
|
|
|
72
72
|
before do
|
|
73
|
-
order.
|
|
74
|
-
order.contents.
|
|
75
|
-
|
|
73
|
+
shipment = order.shipments.create(stock_location: stock_location_1)
|
|
74
|
+
order.contents.add(variant, 1, shipment: shipment)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
context "but no stock in either location" do
|
|
78
|
+
before do
|
|
79
|
+
variant.stock_items.update_all(count_on_hand: 0, backorderable: false)
|
|
80
|
+
end
|
|
81
|
+
include_examples "fails validation"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
context "but no stock in one location" do
|
|
85
|
+
before do
|
|
86
|
+
stock_location_1.stock_items.update_all(count_on_hand: 0, backorderable: false)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
include_examples "fails validation"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
context "with enough stock only across locations" do
|
|
93
|
+
before do
|
|
94
|
+
variant.stock_items.update_all(count_on_hand: 1, backorderable: false)
|
|
95
|
+
end
|
|
96
|
+
include_examples "passes validation"
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
context "but inventory units are finalized" do
|
|
100
|
+
before do
|
|
101
|
+
order.inventory_units.update_all(pending: false)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
include_examples "passes validation"
|
|
76
105
|
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
context "line_item is split across two shipments" do
|
|
110
|
+
let!(:order) { create(:order_with_line_items) }
|
|
111
|
+
let(:line_item) { order.line_items.first }
|
|
112
|
+
let(:variant) { line_item.variant }
|
|
113
|
+
let(:stock_location) { order.shipments.first.stock_location }
|
|
114
|
+
|
|
115
|
+
before do
|
|
116
|
+
shipment2 = order.shipments.create!(stock_location: order.shipments.first.stock_location)
|
|
117
|
+
order.contents.add(variant, 1, shipment: shipment2)
|
|
118
|
+
variant.stock_items.first.update_columns(count_on_hand: count_on_hand, backorderable: false)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
context "and there is just enough stock" do
|
|
122
|
+
let(:count_on_hand) { 2 }
|
|
123
|
+
include_examples "passes validation"
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
context "and there is not enough stock" do
|
|
127
|
+
let(:count_on_hand) { 1 }
|
|
128
|
+
include_examples "fails validation"
|
|
129
|
+
end
|
|
77
130
|
|
|
131
|
+
context "and there is no available stock" do
|
|
132
|
+
let(:count_on_hand) { 0 }
|
|
78
133
|
include_examples "fails validation"
|
|
79
134
|
end
|
|
80
135
|
end
|
|
@@ -65,13 +65,12 @@ RSpec.describe Spree::Tax::ItemAdjuster do
|
|
|
65
65
|
|
|
66
66
|
context 'when there are matching rates for the zone' do
|
|
67
67
|
context 'and all rates have the same tax category as the item' do
|
|
68
|
+
let(:item) { build_stubbed :line_item, order: order, tax_category: item_tax_category }
|
|
68
69
|
let(:item_tax_category) { build_stubbed(:tax_category) }
|
|
69
70
|
let(:rate_1) { create :tax_rate, tax_category: item_tax_category }
|
|
70
71
|
let(:rate_2) { create :tax_rate }
|
|
71
72
|
let(:rates_for_order_zone) { [rate_1, rate_2] }
|
|
72
73
|
|
|
73
|
-
before { allow(item).to receive(:tax_category).and_return(item_tax_category) }
|
|
74
|
-
|
|
75
74
|
it 'creates an adjustment for every matching rate' do
|
|
76
75
|
adjuster.adjust!
|
|
77
76
|
expect(tax_adjustments.length).to eq(1)
|
|
@@ -55,90 +55,5 @@ describe Spree::UnitCancel do
|
|
|
55
55
|
expect { subject }.to raise_error RuntimeError, "Adjustable does not match line item"
|
|
56
56
|
end
|
|
57
57
|
end
|
|
58
|
-
|
|
59
|
-
context "when exchanges are present" do
|
|
60
|
-
let!(:order) { create(:order, ship_address: create(:address)) }
|
|
61
|
-
let!(:product) { create(:product, price: 10.00) }
|
|
62
|
-
let!(:variant) do
|
|
63
|
-
create(:variant, price: 10, product: product, track_inventory: false)
|
|
64
|
-
end
|
|
65
|
-
let!(:shipping_method) { create(:free_shipping_method) }
|
|
66
|
-
let(:exchange_variant) do
|
|
67
|
-
create(:variant, product: variant.product, price: 10, track_inventory: false)
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
before do
|
|
71
|
-
Spree::Config[:expedited_exchanges] = true
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
# This sets up an order with one shipped inventory unit, one unshipped
|
|
75
|
-
# inventory unit, and one unshipped exchange inventory unit.
|
|
76
|
-
before do
|
|
77
|
-
# Complete an order with 1 line item with quantity=2
|
|
78
|
-
order.contents.add(variant, 2)
|
|
79
|
-
order.contents.advance
|
|
80
|
-
create(:payment, order: order, amount: order.total)
|
|
81
|
-
order.payments.reload
|
|
82
|
-
order.contents.advance
|
|
83
|
-
order.complete!
|
|
84
|
-
order.reload
|
|
85
|
-
|
|
86
|
-
# Ship _one_ of the inventory units
|
|
87
|
-
@shipment = order.shipments.first
|
|
88
|
-
@shipped_inventory_unit = order.inventory_units[0]
|
|
89
|
-
@unshipped_inventory_unit = order.inventory_units[1]
|
|
90
|
-
order.shipping.ship(
|
|
91
|
-
inventory_units: [@shipped_inventory_unit],
|
|
92
|
-
stock_location: @shipment.stock_location,
|
|
93
|
-
address: order.ship_address,
|
|
94
|
-
shipping_method: @shipment.shipping_method
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
# Create an expedited exchange for the shipped inventory unit.
|
|
98
|
-
# This generates a new inventory unit attached to the existing line item.
|
|
99
|
-
Spree::ReturnAuthorization.create!(
|
|
100
|
-
order: order,
|
|
101
|
-
stock_location: @shipment.stock_location,
|
|
102
|
-
reason: create(:return_reason),
|
|
103
|
-
return_items: [
|
|
104
|
-
Spree::ReturnItem.new(
|
|
105
|
-
inventory_unit: @shipped_inventory_unit,
|
|
106
|
-
exchange_variant: exchange_variant
|
|
107
|
-
)
|
|
108
|
-
]
|
|
109
|
-
)
|
|
110
|
-
@exchange_inventory_unit = order.inventory_units.reload[2]
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
context 'when canceling an unshipped inventory unit from the original order' do
|
|
114
|
-
subject do
|
|
115
|
-
unit_cancel.compute_amount(@unshipped_inventory_unit.line_item)
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
let(:unit_cancel) do
|
|
119
|
-
Spree::UnitCancel.create!(
|
|
120
|
-
inventory_unit: @unshipped_inventory_unit,
|
|
121
|
-
reason: Spree::UnitCancel::SHORT_SHIP
|
|
122
|
-
)
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
it { is_expected.to eq(-10.00) }
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
context 'when canceling an unshipped exchange inventory unit' do
|
|
129
|
-
subject do
|
|
130
|
-
unit_cancel.compute_amount(@exchange_inventory_unit.line_item)
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
let(:unit_cancel) do
|
|
134
|
-
Spree::UnitCancel.create!(
|
|
135
|
-
inventory_unit: @exchange_inventory_unit,
|
|
136
|
-
reason: Spree::UnitCancel::SHORT_SHIP
|
|
137
|
-
)
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
it { is_expected.to eq(-10.00) }
|
|
141
|
-
end
|
|
142
|
-
end
|
|
143
58
|
end
|
|
144
59
|
end
|
|
@@ -92,7 +92,9 @@ describe Spree::LegacyUser, type: :model do
|
|
|
92
92
|
end
|
|
93
93
|
|
|
94
94
|
it "has payment sources" do
|
|
95
|
-
|
|
95
|
+
Spree::Deprecation.silence do
|
|
96
|
+
expect(user.payment_sources.first.gateway_customer_profile_id).not_to be_empty
|
|
97
|
+
end
|
|
96
98
|
end
|
|
97
99
|
end
|
|
98
100
|
end
|
|
@@ -30,10 +30,16 @@ describe Spree::Variant::VatPriceGenerator do
|
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
it "will not build prices that are already present" do
|
|
33
|
-
variant.prices.build(amount: 11, country_iso: "FR")
|
|
34
|
-
variant.prices.build(amount: 11, country_iso: nil)
|
|
35
33
|
expect { subject }.not_to change { variant.prices.length }
|
|
36
34
|
end
|
|
35
|
+
|
|
36
|
+
# We need to remove the price for FR from the database so it is created in memory, and then run VatPriceGenerator twice to trigger the duplicate price issue.
|
|
37
|
+
it "will not build duplicate prices on multiple runs" do
|
|
38
|
+
variant.prices.where(country_iso: "FR").destroy_all
|
|
39
|
+
variant.reload
|
|
40
|
+
described_class.new(variant).run
|
|
41
|
+
expect { subject }.not_to change { variant.prices.size }
|
|
42
|
+
end
|
|
37
43
|
end
|
|
38
44
|
|
|
39
45
|
context "with no default admin country" do
|
|
@@ -66,17 +66,19 @@ describe Spree::Variant, type: :model do
|
|
|
66
66
|
let!(:high_vat) { create(:tax_rate, included_in_price: true, amount: 0.25, zone: high_vat_zone, tax_category: tax_category) }
|
|
67
67
|
let!(:low_vat) { create(:tax_rate, included_in_price: true, amount: 0.15, zone: low_vat_zone, tax_category: tax_category) }
|
|
68
68
|
|
|
69
|
-
let(:product) {
|
|
69
|
+
let(:product) { build(:product, tax_category: tax_category) }
|
|
70
70
|
|
|
71
|
-
subject(:new_variant) {
|
|
71
|
+
subject(:new_variant) { build(:variant, price: 15) }
|
|
72
72
|
|
|
73
73
|
it "creates the appropriate prices for them" do
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
product.variants << new_variant
|
|
75
|
+
product.save!
|
|
76
76
|
expect(new_variant.prices.find_by(country_iso: "FR").amount).to eq(17.25)
|
|
77
77
|
expect(new_variant.prices.find_by(country_iso: "DE").amount).to eq(18.75)
|
|
78
78
|
expect(new_variant.prices.find_by(country_iso: "DK").amount).to eq(18.75)
|
|
79
79
|
expect(new_variant.prices.find_by(country_iso: nil).amount).to eq(15.00)
|
|
80
|
+
# default price + FR, DE, DK
|
|
81
|
+
expect(new_variant.prices.count).to eq(4)
|
|
80
82
|
end
|
|
81
83
|
|
|
82
84
|
context "when the products price changes" do
|
|
@@ -561,6 +563,16 @@ describe Spree::Variant, type: :model do
|
|
|
561
563
|
end
|
|
562
564
|
end
|
|
563
565
|
end
|
|
566
|
+
|
|
567
|
+
describe "cache clearing on update" do
|
|
568
|
+
it "correctly reports after updating track_inventory" do
|
|
569
|
+
variant.stock_items.first.set_count_on_hand 0
|
|
570
|
+
expect(variant).not_to be_in_stock
|
|
571
|
+
|
|
572
|
+
variant.update!(track_inventory: false)
|
|
573
|
+
expect(variant).to be_in_stock
|
|
574
|
+
end
|
|
575
|
+
end
|
|
564
576
|
end
|
|
565
577
|
|
|
566
578
|
describe '#is_backorderable' do
|