solidus_core 1.1.0 → 1.1.1
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/Gemfile +3 -0
- data/Rakefile +16 -0
- data/script/rails +9 -0
- data/solidus_core.gemspec +48 -0
- data/spec/fixtures/thinking-cat.jpg +0 -0
- data/spec/helpers/base_helper_spec.rb +173 -0
- data/spec/helpers/order_helper_spec.rb +12 -0
- data/spec/helpers/products_helper_spec.rb +208 -0
- data/spec/helpers/taxons_helper_spec.rb +17 -0
- data/spec/lib/calculated_adjustments_spec.rb +7 -0
- data/spec/lib/i18n_spec.rb +106 -0
- data/spec/lib/search/base_spec.rb +86 -0
- data/spec/lib/search/variant_spec.rb +112 -0
- data/spec/lib/spree/core/controller_helpers/auth_spec.rb +66 -0
- data/spec/lib/spree/core/controller_helpers/order_spec.rb +92 -0
- data/spec/lib/spree/core/controller_helpers/payment_parameters_spec.rb +80 -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/current_store_spec.rb +36 -0
- data/spec/lib/spree/core/delegate_belongs_to_spec.rb +24 -0
- data/spec/lib/spree/core/importer/order_spec.rb +431 -0
- data/spec/lib/spree/core/role_configuration_spec.rb +156 -0
- data/spec/lib/spree/core/unreturned_item_charger_spec.rb +130 -0
- data/spec/lib/spree/core/validators/email_spec.rb +48 -0
- data/spec/lib/spree/localized_number_spec.rb +38 -0
- data/spec/lib/spree/migrations_spec.rb +36 -0
- data/spec/lib/spree/money_spec.rb +127 -0
- data/spec/lib/tasks/exchanges_spec.rb +231 -0
- data/spec/lib/tasks/migrations/copy_shipped_shipments_to_cartons_spec.rb +115 -0
- data/spec/lib/tasks/order_capturing_spec.rb +56 -0
- data/spec/mailers/carton_mailer_spec.rb +55 -0
- data/spec/mailers/order_mailer_spec.rb +135 -0
- data/spec/mailers/reimbursement_mailer_spec.rb +40 -0
- data/spec/mailers/test_mailer_spec.rb +15 -0
- data/spec/models/spree/ability_spec.rb +276 -0
- data/spec/models/spree/address_spec.rb +376 -0
- data/spec/models/spree/adjustment_reason_spec.rb +13 -0
- data/spec/models/spree/adjustment_spec.rb +169 -0
- data/spec/models/spree/app_configuration_spec.rb +24 -0
- data/spec/models/spree/asset_spec.rb +24 -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 +60 -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 +30 -0
- data/spec/models/spree/calculator/tiered_flat_rate_spec.rb +36 -0
- data/spec/models/spree/calculator/tiered_percent_spec.rb +47 -0
- data/spec/models/spree/calculator_spec.rb +36 -0
- data/spec/models/spree/carton_spec.rb +133 -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/concerns/ordered_property_value_list_spec.rb +25 -0
- data/spec/models/spree/concerns/user_address_book_spec.rb +332 -0
- data/spec/models/spree/concerns/user_methods_spec.rb +41 -0
- data/spec/models/spree/credit_card_spec.rb +341 -0
- data/spec/models/spree/customer_return_spec.rb +276 -0
- data/spec/models/spree/exchange_spec.rb +79 -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 +104 -0
- data/spec/models/spree/inventory_unit_spec.rb +307 -0
- data/spec/models/spree/item_adjustments_spec.rb +275 -0
- data/spec/models/spree/line_item_spec.rb +199 -0
- data/spec/models/spree/option_type_spec.rb +14 -0
- data/spec/models/spree/option_value_spec.rb +45 -0
- data/spec/models/spree/order/address_spec.rb +50 -0
- data/spec/models/spree/order/adjustments_spec.rb +27 -0
- data/spec/models/spree/order/callbacks_spec.rb +42 -0
- data/spec/models/spree/order/checkout_spec.rb +884 -0
- data/spec/models/spree/order/currency_updater_spec.rb +32 -0
- data/spec/models/spree/order/finalizing_spec.rb +110 -0
- data/spec/models/spree/order/payment_spec.rb +243 -0
- data/spec/models/spree/order/risk_assessment_spec.rb +68 -0
- data/spec/models/spree/order/state_machine_spec.rb +209 -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_cancellations_spec.rb +120 -0
- data/spec/models/spree/order_capturing_spec.rb +150 -0
- data/spec/models/spree/order_contents_spec.rb +307 -0
- data/spec/models/spree/order_inventory_spec.rb +228 -0
- data/spec/models/spree/order_mutex_spec.rb +85 -0
- data/spec/models/spree/order_promotion_spec.rb +31 -0
- data/spec/models/spree/order_shipping_spec.rb +241 -0
- data/spec/models/spree/order_spec.rb +1482 -0
- data/spec/models/spree/order_stock_location_spec.rb +18 -0
- data/spec/models/spree/order_updater_spec.rb +283 -0
- data/spec/models/spree/payment_method/store_credit_spec.rb +294 -0
- data/spec/models/spree/payment_method_spec.rb +147 -0
- data/spec/models/spree/payment_spec.rb +1087 -0
- data/spec/models/spree/permission_sets/base_spec.rb +12 -0
- data/spec/models/spree/permission_sets/configuration_display.rb +82 -0
- data/spec/models/spree/permission_sets/configuration_management_spec.rb +50 -0
- data/spec/models/spree/permission_sets/dashboard_display_spec.rb +22 -0
- data/spec/models/spree/permission_sets/order_display_spec.rb +55 -0
- data/spec/models/spree/permission_sets/order_management_spec.rb +42 -0
- data/spec/models/spree/permission_sets/product_display_spec.rb +60 -0
- data/spec/models/spree/permission_sets/product_management_spec.rb +40 -0
- data/spec/models/spree/permission_sets/promotion_display_spec.rb +40 -0
- data/spec/models/spree/permission_sets/promotion_management_spec.rb +26 -0
- data/spec/models/spree/permission_sets/report_display_spec.rb +24 -0
- data/spec/models/spree/permission_sets/restricted_stock_display_spec.rb +41 -0
- data/spec/models/spree/permission_sets/restricted_stock_management_spec.rb +41 -0
- data/spec/models/spree/permission_sets/restricted_stock_transfer_display_spec.rb +50 -0
- data/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb +160 -0
- data/spec/models/spree/permission_sets/stock_display_spec.rb +24 -0
- data/spec/models/spree/permission_sets/stock_management_spec.rb +22 -0
- data/spec/models/spree/permission_sets/stock_transfer_display_spec.rb +24 -0
- data/spec/models/spree/permission_sets/stock_transfer_management_spec.rb +25 -0
- data/spec/models/spree/permission_sets/user_display_spec.rb +38 -0
- data/spec/models/spree/permission_sets/user_management_spec.rb +48 -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 +294 -0
- data/spec/models/spree/preferences/scoped_store_spec.rb +60 -0
- data/spec/models/spree/preferences/static_model_preferences_spec.rb +78 -0
- data/spec/models/spree/preferences/statically_configurable_spec.rb +60 -0
- data/spec/models/spree/preferences/store_spec.rb +39 -0
- data/spec/models/spree/price_spec.rb +42 -0
- data/spec/models/spree/product/scopes_spec.rb +116 -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_property_spec.rb +18 -0
- data/spec/models/spree/product_spec.rb +504 -0
- data/spec/models/spree/promotion/actions/create_adjustment_spec.rb +96 -0
- data/spec/models/spree/promotion/actions/create_item_adjustments_spec.rb +165 -0
- data/spec/models/spree/promotion/actions/create_quantity_adjustments_spec.rb +115 -0
- data/spec/models/spree/promotion/actions/free_shipping_spec.rb +40 -0
- data/spec/models/spree/promotion/rules/first_order_spec.rb +75 -0
- data/spec/models/spree/promotion/rules/first_repeat_purchase_since_spec.rb +69 -0
- data/spec/models/spree/promotion/rules/item_total_spec.rb +67 -0
- data/spec/models/spree/promotion/rules/nth_order_spec.rb +70 -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 +94 -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_builder_spec.rb +118 -0
- data/spec/models/spree/promotion_category_spec.rb +17 -0
- data/spec/models/spree/promotion_code/code_builder_spec.rb +79 -0
- data/spec/models/spree/promotion_code_spec.rb +187 -0
- data/spec/models/spree/promotion_handler/cart_spec.rb +130 -0
- data/spec/models/spree/promotion_handler/coupon_spec.rb +335 -0
- data/spec/models/spree/promotion_handler/free_shipping_spec.rb +47 -0
- data/spec/models/spree/promotion_handler/page_spec.rb +44 -0
- data/spec/models/spree/promotion_rule_spec.rb +28 -0
- data/spec/models/spree/promotion_spec.rb +776 -0
- data/spec/models/spree/refund_spec.rb +192 -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 +231 -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 +107 -0
- data/spec/models/spree/reimbursement_type/store_credit_spec.rb +97 -0
- data/spec/models/spree/return_authorization_spec.rb +290 -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 +85 -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 +776 -0
- data/spec/models/spree/returns_calculator_spec.rb +14 -0
- data/spec/models/spree/shipment_spec.rb +753 -0
- data/spec/models/spree/shipping_calculator_spec.rb +45 -0
- data/spec/models/spree/shipping_manifest_spec.rb +94 -0
- data/spec/models/spree/shipping_method_spec.rb +88 -0
- data/spec/models/spree/shipping_rate_spec.rb +142 -0
- data/spec/models/spree/state_spec.rb +14 -0
- data/spec/models/spree/stock/availability_validator_spec.rb +83 -0
- data/spec/models/spree/stock/coordinator_spec.rb +116 -0
- data/spec/models/spree/stock/differentiator_spec.rb +39 -0
- data/spec/models/spree/stock/estimator_spec.rb +146 -0
- data/spec/models/spree/stock/inventory_unit_builder_spec.rb +38 -0
- data/spec/models/spree/stock/package_spec.rb +163 -0
- data/spec/models/spree/stock/packer_spec.rb +91 -0
- data/spec/models/spree/stock/prioritizer_spec.rb +125 -0
- data/spec/models/spree/stock/quantifier_spec.rb +115 -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 +50 -0
- data/spec/models/spree/stock/splitter/weight_spec.rb +29 -0
- data/spec/models/spree/stock_item_spec.rb +444 -0
- data/spec/models/spree/stock_location_spec.rb +279 -0
- data/spec/models/spree/stock_movement_spec.rb +56 -0
- data/spec/models/spree/stock_transfer_spec.rb +290 -0
- data/spec/models/spree/store_credit_category_spec.rb +17 -0
- data/spec/models/spree/store_credit_event_spec.rb +314 -0
- data/spec/models/spree/store_credit_spec.rb +876 -0
- data/spec/models/spree/store_spec.rb +55 -0
- data/spec/models/spree/tax_category_spec.rb +27 -0
- data/spec/models/spree/tax_rate_spec.rb +378 -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/transfer_item_spec.rb +264 -0
- data/spec/models/spree/unit_cancel_spec.rb +149 -0
- data/spec/models/spree/user_spec.rb +246 -0
- data/spec/models/spree/validations/db_maximum_length_validator_spec.rb +23 -0
- data/spec/models/spree/variant/scopes_spec.rb +55 -0
- data/spec/models/spree/variant_property_rule_condition_spec.rb +15 -0
- data/spec/models/spree/variant_property_rule_spec.rb +83 -0
- data/spec/models/spree/variant_property_rule_value_spec.rb +18 -0
- data/spec/models/spree/variant_spec.rb +601 -0
- data/spec/models/spree/zone_spec.rb +305 -0
- data/spec/spec_helper.rb +80 -0
- data/spec/support/big_decimal.rb +5 -0
- data/spec/support/concerns/default_price.rb +34 -0
- data/spec/support/dummy_ability.rb +4 -0
- data/spec/support/test_gateway.rb +2 -0
- metadata +242 -2
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Spree::ProductProperty, type: :model do
|
|
4
|
+
context "touching" do
|
|
5
|
+
let(:product_property) { create(:product_property) }
|
|
6
|
+
let(:product) { product_property.product }
|
|
7
|
+
|
|
8
|
+
before do
|
|
9
|
+
product.update_columns(updated_at: 1.day.ago)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
subject { product_property.touch }
|
|
13
|
+
|
|
14
|
+
it "touches the product" do
|
|
15
|
+
expect { subject }.to change { product.reload.updated_at }
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,504 @@
|
|
|
1
|
+
# coding: UTF-8
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
module ThirdParty
|
|
6
|
+
class Extension < Spree::Base
|
|
7
|
+
# nasty hack so we don't have to create a table to back this fake model
|
|
8
|
+
self.table_name = 'spree_products'
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
describe Spree::Product, :type => :model do
|
|
13
|
+
|
|
14
|
+
context 'product instance' do
|
|
15
|
+
let(:product) { create(:product) }
|
|
16
|
+
let(:variant) { create(:variant, :product => product) }
|
|
17
|
+
|
|
18
|
+
context '#duplicate' do
|
|
19
|
+
before do
|
|
20
|
+
allow(product).to receive_messages :taxons => [create(:taxon)]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'duplicates product' do
|
|
24
|
+
clone = product.duplicate
|
|
25
|
+
expect(clone.name).to eq('COPY OF ' + product.name)
|
|
26
|
+
expect(clone.master.sku).to eq('COPY OF ' + product.master.sku)
|
|
27
|
+
expect(clone.taxons).to eq(product.taxons)
|
|
28
|
+
expect(clone.images.size).to eq(product.images.size)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'calls #duplicate_extra' do
|
|
32
|
+
expect_any_instance_of(Spree::Product).to receive(:duplicate_extra) do |product, old_product|
|
|
33
|
+
product.name = old_product.name.reverse
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
clone = product.duplicate
|
|
37
|
+
expect(clone.name).to eq(product.name.reverse)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
context "master variant" do
|
|
42
|
+
|
|
43
|
+
context "when master variant changed" do
|
|
44
|
+
before do
|
|
45
|
+
product.master.sku = "Something changed"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "saves the master" do
|
|
49
|
+
expect(product.master).to receive(:save!)
|
|
50
|
+
product.save
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
context "when master default price changed" do
|
|
55
|
+
before do
|
|
56
|
+
master = product.master
|
|
57
|
+
master.default_price.price = 11
|
|
58
|
+
master.save!
|
|
59
|
+
product.master.default_price.price = 12
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "saves the master" do
|
|
63
|
+
expect(product.master).to receive(:save!)
|
|
64
|
+
product.save
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "saves the default price" do
|
|
68
|
+
expect(product.master.default_price).to receive(:save)
|
|
69
|
+
product.save
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
context "when master variant and price haven't changed" do
|
|
74
|
+
it "does not save the master" do
|
|
75
|
+
expect(product.master).not_to receive(:save!)
|
|
76
|
+
product.save
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
context "product has no variants" do
|
|
82
|
+
context "#destroy" do
|
|
83
|
+
it "should set deleted_at value" do
|
|
84
|
+
product.destroy
|
|
85
|
+
expect(product.deleted_at).not_to be_nil
|
|
86
|
+
expect(product.master.reload.deleted_at).not_to be_nil
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
context "product has variants" do
|
|
92
|
+
before do
|
|
93
|
+
create(:variant, :product => product)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
context "#destroy" do
|
|
97
|
+
it "should set deleted_at value" do
|
|
98
|
+
product.destroy
|
|
99
|
+
expect(product.deleted_at).not_to be_nil
|
|
100
|
+
expect(product.variants_including_master.all? { |v| !v.deleted_at.nil? }).to be true
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
context "#price" do
|
|
106
|
+
# Regression test for #1173
|
|
107
|
+
it 'strips non-price characters' do
|
|
108
|
+
product.price = "$10"
|
|
109
|
+
expect(product.price).to eq(10.0)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
context "#display_price" do
|
|
114
|
+
before { product.price = 10.55 }
|
|
115
|
+
|
|
116
|
+
it "shows the amount" do
|
|
117
|
+
expect(product.display_price.to_s).to eq("$10.55")
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
context "with currency set to JPY" do
|
|
121
|
+
before do
|
|
122
|
+
product.master.default_price.currency = 'JPY'
|
|
123
|
+
product.master.default_price.save!
|
|
124
|
+
Spree::Config[:currency] = 'JPY'
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
it "displays the currency in yen" do
|
|
128
|
+
expect(product.display_price.to_s).to eq("¥11")
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
context "#available?" do
|
|
134
|
+
it "should be available if date is in the past" do
|
|
135
|
+
product.available_on = 1.day.ago
|
|
136
|
+
expect(product).to be_available
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
it "should not be available if date is nil or in the future" do
|
|
140
|
+
product.available_on = nil
|
|
141
|
+
expect(product).not_to be_available
|
|
142
|
+
|
|
143
|
+
product.available_on = 1.day.from_now
|
|
144
|
+
expect(product).not_to be_available
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it "should not be available if destroyed" do
|
|
148
|
+
product.destroy
|
|
149
|
+
expect(product).not_to be_available
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
context "variants_and_option_values" do
|
|
154
|
+
let!(:high) { create(:variant, product: product) }
|
|
155
|
+
let!(:low) { create(:variant, product: product) }
|
|
156
|
+
|
|
157
|
+
before { high.option_values.destroy_all }
|
|
158
|
+
|
|
159
|
+
it "returns only variants with option values" do
|
|
160
|
+
expect(product.variants_and_option_values).to eq([low])
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
describe "#variant_option_values_by_option_type" do
|
|
165
|
+
let(:size) { create(:option_type, name: 'size') }
|
|
166
|
+
let(:length) { create(:option_type, name: 'length') }
|
|
167
|
+
let(:product) { create(:product, option_types: [size, length]) }
|
|
168
|
+
let(:size_small) { create(:option_value, name: 'small', option_type: size, position: 3) }
|
|
169
|
+
let(:size_medium) { create(:option_value, name: 'medium', option_type: size, position: 1) }
|
|
170
|
+
let(:size_large) { create(:option_value, name: 'large', option_type: size, position: 2) }
|
|
171
|
+
let!(:variant) { create(:variant, product: product, option_values: [size_small, size_medium]) }
|
|
172
|
+
|
|
173
|
+
subject { product.variant_option_values_by_option_type }
|
|
174
|
+
|
|
175
|
+
it "returns the option values associated with the product's variants grouped by option type" do
|
|
176
|
+
expect(subject).to eq({ size => [size_medium, size_small] })
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
describe "#find_variant_property_rule" do
|
|
181
|
+
let(:option_value) { create(:option_value) }
|
|
182
|
+
|
|
183
|
+
subject { product.find_variant_property_rule([option_value.id]) }
|
|
184
|
+
|
|
185
|
+
context "a matching rule exists" do
|
|
186
|
+
let!(:rule) do
|
|
187
|
+
create(:variant_property_rule, product: product, option_value: option_value)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
it "returns the rule" do
|
|
191
|
+
expect(subject).to eq rule
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
context "a matching rule doesn't exist" do
|
|
196
|
+
it "returns nil" do
|
|
197
|
+
expect(subject).to be_nil
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
describe 'Variants sorting' do
|
|
203
|
+
let(:master){ product.master }
|
|
204
|
+
|
|
205
|
+
let!(:second) { create(:variant, product: product) }
|
|
206
|
+
let!(:third) { create(:variant, product: product) }
|
|
207
|
+
let!(:first) { create(:variant, product: product) }
|
|
208
|
+
|
|
209
|
+
before do
|
|
210
|
+
first.update_columns(position: 2)
|
|
211
|
+
second.update_columns(position: 3)
|
|
212
|
+
third.update_columns(position: 4)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
context 'without master variant' do
|
|
216
|
+
it 'sorts variants by position' do
|
|
217
|
+
expect(product.variants).to eq([first, second, third])
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
context 'with master variant' do
|
|
222
|
+
it 'sorts variants by position' do
|
|
223
|
+
expect(product.variants_including_master).to eq([master, first, second, third])
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
context "has stock movements" do
|
|
229
|
+
let(:product) { create(:product) }
|
|
230
|
+
let(:variant) { product.master }
|
|
231
|
+
let(:stock_item) { variant.stock_items.first }
|
|
232
|
+
|
|
233
|
+
it "doesnt raise ReadOnlyRecord error" do
|
|
234
|
+
Spree::StockMovement.create!(stock_item: stock_item, quantity: 1)
|
|
235
|
+
expect { product.destroy }.not_to raise_error
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Regression test for #3737
|
|
240
|
+
context "has stock items" do
|
|
241
|
+
let(:product) { create(:product) }
|
|
242
|
+
it "can retrieve stock items" do
|
|
243
|
+
expect(product.master.stock_items.first).not_to be_nil
|
|
244
|
+
expect(product.stock_items.first).not_to be_nil
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
context "slugs" do
|
|
249
|
+
|
|
250
|
+
it "normalizes slug on update validation" do
|
|
251
|
+
product.slug = "hey//joe"
|
|
252
|
+
product.valid?
|
|
253
|
+
expect(product.slug).not_to match "/"
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
it "renames slug on destroy" do
|
|
257
|
+
old_slug = product.slug
|
|
258
|
+
product.destroy
|
|
259
|
+
expect(old_slug).to_not eq product.slug
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
it "validates slug uniqueness" do
|
|
263
|
+
existing_product = product
|
|
264
|
+
new_product = create(:product)
|
|
265
|
+
new_product.slug = existing_product.slug
|
|
266
|
+
|
|
267
|
+
expect(new_product.valid?).to eq false
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
it "falls back to 'name-sku' for slug if regular name-based slug already in use" do
|
|
271
|
+
product1 = build(:product)
|
|
272
|
+
product1.name = "test"
|
|
273
|
+
product1.sku = "123"
|
|
274
|
+
product1.save!
|
|
275
|
+
|
|
276
|
+
product2 = build(:product)
|
|
277
|
+
product2.name = "test"
|
|
278
|
+
product2.sku = "456"
|
|
279
|
+
product2.save!
|
|
280
|
+
|
|
281
|
+
expect(product2.slug).to eq 'test-456'
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
context "associations" do
|
|
286
|
+
describe "product_option_types" do
|
|
287
|
+
it "touches the product instance when an option type is added" do
|
|
288
|
+
expect {
|
|
289
|
+
product.product_option_types.create(option_type: create(:option_type, name: 'new-option-type'))
|
|
290
|
+
product.reload
|
|
291
|
+
}.to change { product.updated_at }
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
it "touches product instance when an option type is removed" do
|
|
295
|
+
product.product_option_types.create(option_type: create(:option_type, name: 'new-option-type'))
|
|
296
|
+
expect {
|
|
297
|
+
product.product_option_types = []
|
|
298
|
+
product.reload
|
|
299
|
+
}.to change { product.updated_at }
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
context "properties" do
|
|
306
|
+
let(:product) { create(:product) }
|
|
307
|
+
|
|
308
|
+
it "should properly assign properties" do
|
|
309
|
+
product.set_property('the_prop', 'value1')
|
|
310
|
+
expect(product.property('the_prop')).to eq('value1')
|
|
311
|
+
|
|
312
|
+
product.set_property('the_prop', 'value2')
|
|
313
|
+
expect(product.property('the_prop')).to eq('value2')
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
it "should not create duplicate properties when set_property is called" do
|
|
317
|
+
expect {
|
|
318
|
+
product.set_property('the_prop', 'value2')
|
|
319
|
+
product.save
|
|
320
|
+
product.reload
|
|
321
|
+
}.not_to change(product.properties, :length)
|
|
322
|
+
|
|
323
|
+
expect {
|
|
324
|
+
product.set_property('the_prop_new', 'value')
|
|
325
|
+
product.save
|
|
326
|
+
product.reload
|
|
327
|
+
expect(product.property('the_prop_new')).to eq('value')
|
|
328
|
+
}.to change { product.properties.length }.by(1)
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
# Regression test for #2455
|
|
332
|
+
it "should not overwrite properties' presentation names" do
|
|
333
|
+
Spree::Property.where(:name => 'foo').first_or_create!(:presentation => "Foo's Presentation Name")
|
|
334
|
+
product.set_property('foo', 'value1')
|
|
335
|
+
product.set_property('bar', 'value2')
|
|
336
|
+
expect(Spree::Property.where(:name => 'foo').first.presentation).to eq("Foo's Presentation Name")
|
|
337
|
+
expect(Spree::Property.where(:name => 'bar').first.presentation).to eq("bar")
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
# Regression test for #4416
|
|
341
|
+
context "#possible_promotions" do
|
|
342
|
+
let!(:promotion) do
|
|
343
|
+
create(:promotion, advertise: true, starts_at: 1.day.ago)
|
|
344
|
+
end
|
|
345
|
+
let!(:rule) do
|
|
346
|
+
Spree::Promotion::Rules::Product.create(
|
|
347
|
+
promotion: promotion,
|
|
348
|
+
products: [product]
|
|
349
|
+
)
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
it "lists the promotion as a possible promotion" do
|
|
353
|
+
expect(product.possible_promotions).to include(promotion)
|
|
354
|
+
end
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
context '#create' do
|
|
359
|
+
let!(:prototype) { create(:prototype) }
|
|
360
|
+
let!(:product) { Spree::Product.new(name: "Foo", price: 1.99, shipping_category_id: create(:shipping_category).id) }
|
|
361
|
+
|
|
362
|
+
before { product.prototype_id = prototype.id }
|
|
363
|
+
|
|
364
|
+
context "when prototype is supplied" do
|
|
365
|
+
it "should create properties based on the prototype" do
|
|
366
|
+
product.save
|
|
367
|
+
expect(product.properties.count).to eq(1)
|
|
368
|
+
end
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
context "when prototype with option types is supplied" do
|
|
372
|
+
def build_option_type_with_values(name, values)
|
|
373
|
+
ot = create(:option_type, :name => name)
|
|
374
|
+
values.each do |val|
|
|
375
|
+
ot.option_values.create(:name => val.downcase, :presentation => val)
|
|
376
|
+
end
|
|
377
|
+
ot
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
let(:prototype) do
|
|
381
|
+
size = build_option_type_with_values("size", %w(Small Medium Large))
|
|
382
|
+
create(:prototype, :name => "Size", :option_types => [ size ])
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
let(:option_values_hash) do
|
|
386
|
+
hash = {}
|
|
387
|
+
prototype.option_types.each do |i|
|
|
388
|
+
hash[i.id.to_s] = i.option_value_ids
|
|
389
|
+
end
|
|
390
|
+
hash
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
it "should create option types based on the prototype" do
|
|
394
|
+
product.save
|
|
395
|
+
expect(product.option_type_ids.length).to eq(1)
|
|
396
|
+
expect(product.option_type_ids).to eq(prototype.option_type_ids)
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
it "should create product option types based on the prototype" do
|
|
400
|
+
product.save
|
|
401
|
+
expect(product.product_option_types.pluck(:option_type_id)).to eq(prototype.option_type_ids)
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
it "should create variants from an option values hash with one option type" do
|
|
405
|
+
product.option_values_hash = option_values_hash
|
|
406
|
+
product.save
|
|
407
|
+
expect(product.variants.length).to eq(3)
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
it "should still create variants when option_values_hash is given but prototype id is nil" do
|
|
411
|
+
product.option_values_hash = option_values_hash
|
|
412
|
+
product.prototype_id = nil
|
|
413
|
+
product.save
|
|
414
|
+
expect(product.option_type_ids.length).to eq(1)
|
|
415
|
+
expect(product.option_type_ids).to eq(prototype.option_type_ids)
|
|
416
|
+
expect(product.variants.length).to eq(3)
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
it "should create variants from an option values hash with multiple option types" do
|
|
420
|
+
color = build_option_type_with_values("color", %w(Red Green Blue))
|
|
421
|
+
logo = build_option_type_with_values("logo", %w(Ruby Rails Nginx))
|
|
422
|
+
option_values_hash[color.id.to_s] = color.option_value_ids
|
|
423
|
+
option_values_hash[logo.id.to_s] = logo.option_value_ids
|
|
424
|
+
product.option_values_hash = option_values_hash
|
|
425
|
+
product.save
|
|
426
|
+
product.reload
|
|
427
|
+
expect(product.option_type_ids.length).to eq(3)
|
|
428
|
+
expect(product.variants.length).to eq(27)
|
|
429
|
+
end
|
|
430
|
+
end
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
context "#images" do
|
|
434
|
+
let(:product) { create(:product) }
|
|
435
|
+
let(:image) { File.open(File.expand_path('../../../fixtures/thinking-cat.jpg', __FILE__)) }
|
|
436
|
+
let(:params) { {:viewable_id => product.master.id, :viewable_type => 'Spree::Variant', :attachment => image, :alt => "position 2", :position => 2} }
|
|
437
|
+
|
|
438
|
+
before do
|
|
439
|
+
Spree::Image.create(params)
|
|
440
|
+
Spree::Image.create(params.merge({:alt => "position 1", :position => 1}))
|
|
441
|
+
Spree::Image.create(params.merge({:viewable_type => 'ThirdParty::Extension', :alt => "position 1", :position => 2}))
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
it "only looks for variant images" do
|
|
445
|
+
expect(product.images.size).to eq(2)
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
it "should be sorted by position" do
|
|
449
|
+
expect(product.images.pluck(:alt)).to eq(["position 1", "position 2"])
|
|
450
|
+
end
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
# Regression tests for #2352
|
|
454
|
+
context "classifications and taxons" do
|
|
455
|
+
it "is joined through classifications" do
|
|
456
|
+
reflection = Spree::Product.reflect_on_association(:taxons)
|
|
457
|
+
expect(reflection.options[:through]).to eq(:classifications)
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
it "will delete all classifications" do
|
|
461
|
+
reflection = Spree::Product.reflect_on_association(:classifications)
|
|
462
|
+
expect(reflection.options[:dependent]).to eq(:delete_all)
|
|
463
|
+
end
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
context '#total_on_hand' do
|
|
467
|
+
it 'should be infinite if track_inventory_levels is false' do
|
|
468
|
+
Spree::Config[:track_inventory_levels] = false
|
|
469
|
+
expect(build(:product, :variants_including_master => [build(:master_variant)]).total_on_hand).to eql(Float::INFINITY)
|
|
470
|
+
end
|
|
471
|
+
|
|
472
|
+
it 'should be infinite if variant is on demand' do
|
|
473
|
+
Spree::Config[:track_inventory_levels] = true
|
|
474
|
+
expect(build(:product, :variants_including_master => [build(:on_demand_master_variant)]).total_on_hand).to eql(Float::INFINITY)
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
it 'should return sum of stock items count_on_hand' do
|
|
478
|
+
product = create(:product)
|
|
479
|
+
product.stock_items.first.set_count_on_hand 5
|
|
480
|
+
product.variants_including_master(true) # force load association
|
|
481
|
+
expect(product.total_on_hand).to eql(5)
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
it 'should return sum of stock items count_on_hand when variants_including_master is not loaded' do
|
|
485
|
+
product = create(:product)
|
|
486
|
+
product.stock_items.first.set_count_on_hand 5
|
|
487
|
+
expect(product.reload.total_on_hand).to eql(5)
|
|
488
|
+
end
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
# Regression spec for https://github.com/spree/spree/issues/5588
|
|
492
|
+
context '#validate_master when duplicate SKUs entered' do
|
|
493
|
+
let!(:first_product) { create(:product, sku: 'a-sku') }
|
|
494
|
+
let(:second_product) { build(:product, sku: 'a-sku') }
|
|
495
|
+
|
|
496
|
+
subject { second_product }
|
|
497
|
+
it { is_expected.to be_invalid }
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
it "initializes a master variant when building a product" do
|
|
501
|
+
product = Spree::Product.new
|
|
502
|
+
expect(product.master.is_master).to be true
|
|
503
|
+
end
|
|
504
|
+
end
|