spree_core 3.2.1 → 3.2.2
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/lib/spree/core/version.rb +1 -1
- data/spree_core.gemspec +1 -1
- metadata +3 -206
- data/spec/fixtures/microdata.html +0 -22
- data/spec/fixtures/microdata_itemref.html +0 -15
- data/spec/fixtures/microdata_no_itemscope.html +0 -20
- data/spec/fixtures/thinking-cat.jpg +0 -0
- data/spec/helpers/base_helper_spec.rb +0 -200
- data/spec/helpers/products_helper_spec.rb +0 -289
- data/spec/lib/calculated_adjustments_spec.rb +0 -7
- data/spec/lib/i18n_spec.rb +0 -123
- data/spec/lib/search/base_spec.rb +0 -86
- data/spec/lib/spree/core/controller_helpers/auth_spec.rb +0 -103
- data/spec/lib/spree/core/controller_helpers/order_spec.rb +0 -110
- data/spec/lib/spree/core/controller_helpers/search_spec.rb +0 -17
- data/spec/lib/spree/core/controller_helpers/store_spec.rb +0 -72
- data/spec/lib/spree/core/controller_helpers/strong_parameters_spec.rb +0 -39
- data/spec/lib/spree/core/delegate_belongs_to_spec.rb +0 -22
- data/spec/lib/spree/core/importer/order_spec.rb +0 -605
- data/spec/lib/spree/core/number_generator_spec.rb +0 -175
- data/spec/lib/spree/core/token_generator_spec.rb +0 -24
- data/spec/lib/spree/core/validators/email_spec.rb +0 -53
- data/spec/lib/spree/core_spec.rb +0 -23
- data/spec/lib/spree/localized_number_spec.rb +0 -48
- data/spec/lib/spree/migrations_spec.rb +0 -36
- data/spec/lib/spree/money_spec.rb +0 -122
- data/spec/lib/tasks/exchanges_spec.rb +0 -136
- data/spec/mailers/order_mailer_spec.rb +0 -122
- data/spec/mailers/reimbursement_mailer_spec.rb +0 -47
- data/spec/mailers/shipment_mailer_spec.rb +0 -81
- data/spec/mailers/test_mailer_spec.rb +0 -38
- data/spec/models/option_type_prototype_spec.rb +0 -9
- data/spec/models/spree/ability_spec.rb +0 -251
- data/spec/models/spree/address_spec.rb +0 -402
- data/spec/models/spree/adjustable/adjuster/base_spec.rb +0 -10
- data/spec/models/spree/adjustable/adjuster/promotion_spec.rb +0 -211
- data/spec/models/spree/adjustable/adjuster/tax_spec.rb +0 -86
- data/spec/models/spree/adjustable/adjustments_updater_spec.rb +0 -26
- data/spec/models/spree/adjustment_spec.rb +0 -189
- data/spec/models/spree/app_configuration_spec.rb +0 -26
- data/spec/models/spree/asset_spec.rb +0 -28
- data/spec/models/spree/calculator/default_tax_spec.rb +0 -152
- data/spec/models/spree/calculator/flat_percent_item_total_spec.rb +0 -25
- data/spec/models/spree/calculator/flat_rate_spec.rb +0 -47
- data/spec/models/spree/calculator/flexi_rate_spec.rb +0 -41
- data/spec/models/spree/calculator/percent_on_line_item_spec.rb +0 -15
- data/spec/models/spree/calculator/price_sack_spec.rb +0 -30
- data/spec/models/spree/calculator/refunds/default_refund_amount_spec.rb +0 -47
- data/spec/models/spree/calculator/shipping.rb +0 -8
- data/spec/models/spree/calculator/shipping/flat_percent_item_total_spec.rb +0 -23
- data/spec/models/spree/calculator/shipping/flat_rate_spec.rb +0 -13
- data/spec/models/spree/calculator/shipping/flexi_rate_spec.rb +0 -52
- data/spec/models/spree/calculator/shipping/per_item_spec.rb +0 -20
- data/spec/models/spree/calculator/shipping/price_sack_spec.rb +0 -29
- data/spec/models/spree/calculator/tiered_flat_rate_spec.rb +0 -40
- data/spec/models/spree/calculator/tiered_percent_spec.rb +0 -51
- data/spec/models/spree/calculator_spec.rb +0 -69
- data/spec/models/spree/classification_spec.rb +0 -93
- data/spec/models/spree/concerns/display_money_spec.rb +0 -43
- data/spec/models/spree/concerns/user_methods_spec.rb +0 -82
- data/spec/models/spree/concerns/vat_price_calculation_spec.rb +0 -66
- data/spec/models/spree/country_spec.rb +0 -55
- data/spec/models/spree/credit_card_spec.rb +0 -328
- data/spec/models/spree/customer_return_spec.rb +0 -240
- data/spec/models/spree/exchange_spec.rb +0 -75
- data/spec/models/spree/gateway/bogus_simple.rb +0 -20
- data/spec/models/spree/gateway/bogus_spec.rb +0 -13
- data/spec/models/spree/gateway_spec.rb +0 -61
- data/spec/models/spree/image_spec.rb +0 -8
- data/spec/models/spree/inventory_unit_spec.rb +0 -256
- data/spec/models/spree/line_item_spec.rb +0 -346
- data/spec/models/spree/option_type_spec.rb +0 -14
- data/spec/models/spree/option_value_spec.rb +0 -18
- data/spec/models/spree/order/address_spec.rb +0 -50
- data/spec/models/spree/order/adjustments_spec.rb +0 -29
- data/spec/models/spree/order/callbacks_spec.rb +0 -42
- data/spec/models/spree/order/checkout_spec.rb +0 -770
- data/spec/models/spree/order/currency_updater_spec.rb +0 -32
- data/spec/models/spree/order/finalizing_spec.rb +0 -114
- data/spec/models/spree/order/helpers_spec.rb +0 -5
- data/spec/models/spree/order/payment_spec.rb +0 -214
- data/spec/models/spree/order/risk_assessment_spec.rb +0 -84
- data/spec/models/spree/order/shipments_spec.rb +0 -43
- data/spec/models/spree/order/state_machine_spec.rb +0 -212
- data/spec/models/spree/order/store_credit_spec.rb +0 -426
- data/spec/models/spree/order/tax_spec.rb +0 -84
- data/spec/models/spree/order/totals_spec.rb +0 -24
- data/spec/models/spree/order/updating_spec.rb +0 -18
- data/spec/models/spree/order/validations_spec.rb +0 -15
- data/spec/models/spree/order_contents_spec.rb +0 -297
- data/spec/models/spree/order_inventory_spec.rb +0 -239
- data/spec/models/spree/order_merger_spec.rb +0 -135
- data/spec/models/spree/order_spec.rb +0 -1046
- data/spec/models/spree/order_updater_spec.rb +0 -305
- data/spec/models/spree/payment/gateway_options_spec.rb +0 -127
- data/spec/models/spree/payment/store_credit_spec.rb +0 -60
- data/spec/models/spree/payment_method/store_credit_spec.rb +0 -291
- data/spec/models/spree/payment_method_spec.rb +0 -103
- data/spec/models/spree/payment_spec.rb +0 -919
- data/spec/models/spree/preference_spec.rb +0 -80
- data/spec/models/spree/preferences/configuration_spec.rb +0 -30
- data/spec/models/spree/preferences/preferable_spec.rb +0 -344
- data/spec/models/spree/preferences/scoped_store_spec.rb +0 -58
- data/spec/models/spree/preferences/store_spec.rb +0 -46
- data/spec/models/spree/price_spec.rb +0 -128
- data/spec/models/spree/product/scopes_spec.rb +0 -183
- data/spec/models/spree/product_duplicator_spec.rb +0 -103
- data/spec/models/spree/product_filter_spec.rb +0 -26
- data/spec/models/spree/product_option_type_spec.rb +0 -9
- data/spec/models/spree/product_promotion_rule_spec.rb +0 -9
- data/spec/models/spree/product_property_spec.rb +0 -26
- data/spec/models/spree/product_spec.rb +0 -629
- data/spec/models/spree/promotion/actions/create_adjustment_spec.rb +0 -113
- data/spec/models/spree/promotion/actions/create_item_adjustments_spec.rb +0 -148
- data/spec/models/spree/promotion/actions/create_line_items_spec.rb +0 -86
- data/spec/models/spree/promotion/actions/free_shipping_spec.rb +0 -36
- data/spec/models/spree/promotion/rules/country_spec.rb +0 -36
- data/spec/models/spree/promotion/rules/first_order_spec.rb +0 -75
- data/spec/models/spree/promotion/rules/item_total_spec.rb +0 -282
- data/spec/models/spree/promotion/rules/one_use_per_user_spec.rb +0 -42
- data/spec/models/spree/promotion/rules/option_value_spec.rb +0 -90
- data/spec/models/spree/promotion/rules/product_spec.rb +0 -143
- data/spec/models/spree/promotion/rules/taxon_spec.rb +0 -102
- data/spec/models/spree/promotion/rules/user_logged_in_spec.rb +0 -27
- data/spec/models/spree/promotion/rules/user_spec.rb +0 -45
- data/spec/models/spree/promotion_action_spec.rb +0 -10
- data/spec/models/spree/promotion_category_spec.rb +0 -17
- data/spec/models/spree/promotion_handler/cart_spec.rb +0 -102
- data/spec/models/spree/promotion_handler/coupon_spec.rb +0 -323
- data/spec/models/spree/promotion_handler/free_shipping_spec.rb +0 -48
- data/spec/models/spree/promotion_handler/page_spec.rb +0 -44
- data/spec/models/spree/promotion_rule_spec.rb +0 -29
- data/spec/models/spree/promotion_rule_taxon_spec.rb +0 -9
- data/spec/models/spree/promotion_rule_user_spec.rb +0 -9
- data/spec/models/spree/promotion_spec.rb +0 -679
- data/spec/models/spree/property_prototype_spec.rb +0 -9
- data/spec/models/spree/property_spec.rb +0 -5
- data/spec/models/spree/prototype_spec.rb +0 -5
- data/spec/models/spree/prototype_taxon_spec.rb +0 -9
- data/spec/models/spree/refund_reason_spec.rb +0 -20
- data/spec/models/spree/refund_spec.rb +0 -195
- data/spec/models/spree/reimbursement/credit_spec.rb +0 -36
- data/spec/models/spree/reimbursement/reimbursement_type_engine_spec.rb +0 -140
- data/spec/models/spree/reimbursement/reimbursement_type_validator_spec.rb +0 -83
- data/spec/models/spree/reimbursement_performer_spec.rb +0 -30
- data/spec/models/spree/reimbursement_spec.rb +0 -188
- data/spec/models/spree/reimbursement_tax_calculator_spec.rb +0 -63
- data/spec/models/spree/reimbursement_type/credit_spec.rb +0 -53
- data/spec/models/spree/reimbursement_type/exchange_spec.rb +0 -46
- data/spec/models/spree/reimbursement_type/original_payment_spec.rb +0 -55
- data/spec/models/spree/reimbursement_type/store_credit_spec.rb +0 -101
- data/spec/models/spree/return_authorization_reason_spec.rb +0 -7
- data/spec/models/spree/return_authorization_spec.rb +0 -230
- data/spec/models/spree/return_item/eligibility_validator/default_spec.rb +0 -77
- data/spec/models/spree/return_item/eligibility_validator/inventory_shipped_spec.rb +0 -58
- data/spec/models/spree/return_item/eligibility_validator/no_reimbursements_spec.rb +0 -61
- data/spec/models/spree/return_item/eligibility_validator/order_completed_spec.rb +0 -32
- data/spec/models/spree/return_item/eligibility_validator/rma_required_spec.rb +0 -29
- data/spec/models/spree/return_item/eligibility_validator/time_since_purchase_spec.rb +0 -35
- data/spec/models/spree/return_item/exchange_variant_eligibility/same_option_value_spec.rb +0 -65
- data/spec/models/spree/return_item/exchange_variant_eligibility/same_product_spec.rb +0 -43
- data/spec/models/spree/return_item_spec.rb +0 -731
- data/spec/models/spree/returns_calculator_spec.rb +0 -14
- data/spec/models/spree/role_spec.rb +0 -7
- data/spec/models/spree/shipment_spec.rb +0 -742
- data/spec/models/spree/shipping_calculator_spec.rb +0 -45
- data/spec/models/spree/shipping_category_spec.rb +0 -19
- data/spec/models/spree/shipping_method_spec.rb +0 -95
- data/spec/models/spree/shipping_rate_spec.rb +0 -140
- data/spec/models/spree/state_spec.rb +0 -29
- data/spec/models/spree/stock/availability_validator_spec.rb +0 -36
- data/spec/models/spree/stock/content_item_spec.rb +0 -31
- data/spec/models/spree/stock/coordinator_spec.rb +0 -61
- data/spec/models/spree/stock/differentiator_spec.rb +0 -39
- data/spec/models/spree/stock/estimator_spec.rb +0 -202
- data/spec/models/spree/stock/inventory_unit_builder_spec.rb +0 -38
- data/spec/models/spree/stock/package_spec.rb +0 -182
- data/spec/models/spree/stock/packer_spec.rb +0 -70
- data/spec/models/spree/stock/prioritizer_spec.rb +0 -125
- data/spec/models/spree/stock/quantifier_spec.rb +0 -126
- data/spec/models/spree/stock/splitter/backordered_spec.rb +0 -29
- data/spec/models/spree/stock/splitter/base_spec.rb +0 -21
- data/spec/models/spree/stock/splitter/shipping_category_spec.rb +0 -47
- data/spec/models/spree/stock/splitter/weight_spec.rb +0 -32
- data/spec/models/spree/stock_item_spec.rb +0 -432
- data/spec/models/spree/stock_location_spec.rb +0 -243
- data/spec/models/spree/stock_movement_spec.rb +0 -120
- data/spec/models/spree/stock_transfer_spec.rb +0 -50
- data/spec/models/spree/store_credit_event_spec.rb +0 -101
- data/spec/models/spree/store_credit_spec.rb +0 -786
- data/spec/models/spree/store_spec.rb +0 -78
- data/spec/models/spree/tax_category_spec.rb +0 -32
- data/spec/models/spree/tax_rate_spec.rb +0 -561
- data/spec/models/spree/taxon_spec.rb +0 -85
- data/spec/models/spree/taxonomy_spec.rb +0 -18
- data/spec/models/spree/tracker_spec.rb +0 -21
- data/spec/models/spree/user_spec.rb +0 -203
- data/spec/models/spree/variant_spec.rb +0 -818
- data/spec/models/spree/zone_member_spec.rb +0 -38
- data/spec/models/spree/zone_spec.rb +0 -472
- data/spec/spec_helper.rb +0 -79
- data/spec/support/big_decimal.rb +0 -5
- data/spec/support/concerns/adjustment_source.rb +0 -23
- data/spec/support/concerns/default_price.rb +0 -37
- data/spec/support/rake.rb +0 -13
- data/spec/support/test_gateway.rb +0 -2
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'spree/core/product_filters'
|
|
3
|
-
|
|
4
|
-
describe 'product filters', type: :model do
|
|
5
|
-
# Regression test for #1709
|
|
6
|
-
context 'finds products filtered by brand' do
|
|
7
|
-
let(:product) { create(:product) }
|
|
8
|
-
before do
|
|
9
|
-
property = Spree::Property.create!(name: "brand", presentation: "brand")
|
|
10
|
-
product.set_property("brand", "Nike")
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
it "does not attempt to call value method on Arel::Table" do
|
|
14
|
-
expect { Spree::Core::ProductFilters.brand_filter }.not_to raise_error
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
it "can find products in the 'Nike' brand" do
|
|
18
|
-
expect(Spree::Product.brand_any("Nike")).to include(product)
|
|
19
|
-
end
|
|
20
|
-
it "sorts products without brand specified" do
|
|
21
|
-
product.set_property("brand", "Nike")
|
|
22
|
-
create(:product).set_property("brand", nil)
|
|
23
|
-
expect { Spree::Core::ProductFilters.brand_filter[:labels] }.not_to raise_error
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
describe Spree::ProductOptionType do
|
|
4
|
-
describe 'Validations' do
|
|
5
|
-
it { is_expected.to validate_presence_of(:product) }
|
|
6
|
-
it { is_expected.to validate_presence_of(:option_type) }
|
|
7
|
-
it { is_expected.to validate_uniqueness_of(:product_id).scoped_to(:option_type_id).allow_nil }
|
|
8
|
-
end
|
|
9
|
-
end
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
describe Spree::ProductPromotionRule do
|
|
4
|
-
describe 'Validations' do
|
|
5
|
-
it { is_expected.to validate_presence_of(:product) }
|
|
6
|
-
it { is_expected.to validate_presence_of(:promotion_rule) }
|
|
7
|
-
it { is_expected.to validate_uniqueness_of(:product_id).scoped_to(:promotion_rule_id).allow_nil }
|
|
8
|
-
end
|
|
9
|
-
end
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
describe Spree::ProductProperty, type: :model do
|
|
4
|
-
context "touching" do
|
|
5
|
-
it "should update product" do
|
|
6
|
-
pp = create(:product_property)
|
|
7
|
-
expect(pp.product).to receive(:touch)
|
|
8
|
-
pp.touch
|
|
9
|
-
end
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
context 'property_name=' do
|
|
13
|
-
before do
|
|
14
|
-
@pp = create(:product_property)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
it "should assign property" do
|
|
18
|
-
@pp.property_name = "Size"
|
|
19
|
-
expect(@pp.property.name).to eq('Size')
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
context 'ransackable_associations' do
|
|
24
|
-
it { expect(Spree::ProductProperty.whitelisted_ransackable_associations).to include('property') }
|
|
25
|
-
end
|
|
26
|
-
end
|
|
@@ -1,629 +0,0 @@
|
|
|
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
|
-
describe 'Associations' do
|
|
15
|
-
it 'should have many promotions' do
|
|
16
|
-
is_expected.to have_many(:promotions).
|
|
17
|
-
class_name('Spree::Promotion').through(:promotion_rules)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
it 'should have many possible_promotions' do
|
|
21
|
-
is_expected.to have_many(:possible_promotions).
|
|
22
|
-
class_name('Spree::Promotion').through(:promotion_rules).source(:promotion)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
it do
|
|
26
|
-
is_expected.to have_many(:variants).
|
|
27
|
-
class_name('Spree::Variant').
|
|
28
|
-
inverse_of(:product).
|
|
29
|
-
conditions(is_master: false).
|
|
30
|
-
order(:position)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
it do
|
|
34
|
-
is_expected.to have_many(:variants_including_master).
|
|
35
|
-
class_name('Spree::Variant').
|
|
36
|
-
inverse_of(:product).
|
|
37
|
-
order(:position)
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
context 'product instance' do
|
|
42
|
-
let(:product) { create(:product) }
|
|
43
|
-
let(:variant) { create(:variant, product: product) }
|
|
44
|
-
|
|
45
|
-
context '#duplicate' do
|
|
46
|
-
before do
|
|
47
|
-
allow(product).to receive_messages taxons: [create(:taxon)]
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
it 'duplicates product' do
|
|
51
|
-
clone = product.duplicate
|
|
52
|
-
expect(clone.name).to eq('COPY OF ' + product.name)
|
|
53
|
-
expect(clone.master.sku).to eq('COPY OF ' + product.master.sku)
|
|
54
|
-
expect(clone.taxons).to eq(product.taxons)
|
|
55
|
-
expect(clone.images.size).to eq(product.images.size)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
it 'calls #duplicate_extra' do
|
|
59
|
-
expect_any_instance_of(Spree::Product).to receive(:duplicate_extra)
|
|
60
|
-
.with(product)
|
|
61
|
-
expect(product).to_not receive(:duplicate_extra)
|
|
62
|
-
product.duplicate
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
context "master variant" do
|
|
67
|
-
|
|
68
|
-
context "when master variant changed" do
|
|
69
|
-
before do
|
|
70
|
-
product.master.sku = "Something changed"
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
it "saves the master" do
|
|
74
|
-
expect(product.master).to receive(:save!)
|
|
75
|
-
product.save
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
context "when master default price changed" do
|
|
80
|
-
before do
|
|
81
|
-
master = product.master
|
|
82
|
-
master.default_price.price = 11
|
|
83
|
-
master.save!
|
|
84
|
-
product.master.default_price.price = 12
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
it "saves the master" do
|
|
88
|
-
expect(product.master).to receive(:save!)
|
|
89
|
-
product.save
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
it "saves the default price" do
|
|
93
|
-
expect(product.master.default_price).to receive(:save)
|
|
94
|
-
product.save
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
context "when master variant and price haven't changed" do
|
|
99
|
-
it "does not save the master" do
|
|
100
|
-
expect(product.master).not_to receive(:save!)
|
|
101
|
-
product.save
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
context "product has no variants" do
|
|
107
|
-
context "#destroy" do
|
|
108
|
-
it "should set deleted_at value" do
|
|
109
|
-
product.destroy
|
|
110
|
-
expect(product.deleted_at).not_to be_nil
|
|
111
|
-
expect(product.master.reload.deleted_at).not_to be_nil
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
context "product has variants" do
|
|
117
|
-
before do
|
|
118
|
-
create(:variant, product: product)
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
context "#destroy" do
|
|
122
|
-
it "should set deleted_at value" do
|
|
123
|
-
product.destroy
|
|
124
|
-
expect(product.deleted_at).not_to be_nil
|
|
125
|
-
expect(product.variants_including_master.all? { |v| !v.deleted_at.nil? }).to be true
|
|
126
|
-
end
|
|
127
|
-
end
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
context "#price" do
|
|
131
|
-
# Regression test for #1173
|
|
132
|
-
it 'strips non-price characters' do
|
|
133
|
-
product.price = "$10"
|
|
134
|
-
expect(product.price).to eq(10.0)
|
|
135
|
-
end
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
context "#display_price" do
|
|
139
|
-
before { product.price = 10.55 }
|
|
140
|
-
|
|
141
|
-
it "shows the amount" do
|
|
142
|
-
expect(product.display_price.to_s).to eq("$10.55")
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
context "with currency set to JPY" do
|
|
146
|
-
before do
|
|
147
|
-
product.master.default_price.currency = 'JPY'
|
|
148
|
-
product.master.default_price.save!
|
|
149
|
-
Spree::Config[:currency] = 'JPY'
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
it "displays the currency in yen" do
|
|
153
|
-
expect(product.display_price.to_s).to eq("¥11")
|
|
154
|
-
end
|
|
155
|
-
end
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
context "#available?" do
|
|
159
|
-
it "should be available if date is in the past" do
|
|
160
|
-
product.available_on = 1.day.ago
|
|
161
|
-
expect(product).to be_available
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
it "should not be available if date is nil or in the future" do
|
|
165
|
-
product.available_on = nil
|
|
166
|
-
expect(product).not_to be_available
|
|
167
|
-
|
|
168
|
-
product.available_on = 1.day.from_now
|
|
169
|
-
expect(product).not_to be_available
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
it "should not be available if destroyed" do
|
|
173
|
-
product.destroy
|
|
174
|
-
expect(product).not_to be_available
|
|
175
|
-
end
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
context "#can_supply?" do
|
|
179
|
-
it "should be true" do
|
|
180
|
-
expect(product.can_supply?).to be(true)
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
it "should be false" do
|
|
184
|
-
product.variants_including_master.each { |v| v.stock_items.update_all count_on_hand: 0, backorderable: false }
|
|
185
|
-
expect(product.can_supply?).to be(false)
|
|
186
|
-
end
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
context "variants_and_option_values" do
|
|
190
|
-
let!(:high) { create(:variant, product: product) }
|
|
191
|
-
let!(:low) { create(:variant, product: product) }
|
|
192
|
-
|
|
193
|
-
before { high.option_values.destroy_all }
|
|
194
|
-
|
|
195
|
-
it "returns only variants with option values" do
|
|
196
|
-
expect(product.variants_and_option_values).to eq([low])
|
|
197
|
-
end
|
|
198
|
-
end
|
|
199
|
-
|
|
200
|
-
context "has stock movements" do
|
|
201
|
-
let(:variant) { product.master }
|
|
202
|
-
let(:stock_item) { variant.stock_items.first }
|
|
203
|
-
|
|
204
|
-
it "doesnt raise ReadOnlyRecord error" do
|
|
205
|
-
Spree::StockMovement.create!(stock_item: stock_item, quantity: 1)
|
|
206
|
-
expect { product.destroy }.not_to raise_error
|
|
207
|
-
end
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
# Regression test for #3737
|
|
211
|
-
context "has stock items" do
|
|
212
|
-
it "can retrieve stock items" do
|
|
213
|
-
expect(product.master.stock_items.first).not_to be_nil
|
|
214
|
-
expect(product.stock_items.first).not_to be_nil
|
|
215
|
-
end
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
context "slugs" do
|
|
219
|
-
|
|
220
|
-
it "normalizes slug on update validation" do
|
|
221
|
-
product.slug = "hey//joe"
|
|
222
|
-
product.valid?
|
|
223
|
-
expect(product.slug).not_to match "/"
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
it "stores old slugs in FriendlyIds history" do
|
|
227
|
-
# create_slug is a private method, included by FriendlyId::History
|
|
228
|
-
# it's effect is rather complex and dependent on state and config.
|
|
229
|
-
# However, when a new slug is set, it should call slugs.create!
|
|
230
|
-
expect(product.slugs).to receive(:create!)
|
|
231
|
-
# Set it, otherwise the create_slug method avoids writing a new one
|
|
232
|
-
product.slug = "custom-slug"
|
|
233
|
-
product.run_callbacks :save
|
|
234
|
-
end
|
|
235
|
-
|
|
236
|
-
context "when product destroyed" do
|
|
237
|
-
|
|
238
|
-
it "renames slug" do
|
|
239
|
-
expect { product.destroy }.to change { product.slug }
|
|
240
|
-
end
|
|
241
|
-
|
|
242
|
-
context "when slug is already at or near max length" do
|
|
243
|
-
|
|
244
|
-
before do
|
|
245
|
-
product.slug = "x" * 255
|
|
246
|
-
product.save!
|
|
247
|
-
end
|
|
248
|
-
|
|
249
|
-
it "truncates renamed slug to ensure it remains within length limit" do
|
|
250
|
-
product.destroy
|
|
251
|
-
expect(product.slug.length).to eq 255
|
|
252
|
-
end
|
|
253
|
-
|
|
254
|
-
end
|
|
255
|
-
|
|
256
|
-
end
|
|
257
|
-
|
|
258
|
-
it "validates slug uniqueness" do
|
|
259
|
-
existing_product = product
|
|
260
|
-
new_product = create(:product)
|
|
261
|
-
new_product.slug = existing_product.slug
|
|
262
|
-
|
|
263
|
-
expect(new_product.valid?).to eq false
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
it "falls back to 'name-sku' for slug if regular name-based slug already in use" do
|
|
267
|
-
product1 = build(:product)
|
|
268
|
-
product1.name = "test"
|
|
269
|
-
product1.sku = "123"
|
|
270
|
-
product1.save!
|
|
271
|
-
|
|
272
|
-
product2 = build(:product)
|
|
273
|
-
product2.name = "test"
|
|
274
|
-
product2.sku = "456"
|
|
275
|
-
product2.save!
|
|
276
|
-
|
|
277
|
-
expect(product2.slug).to eq 'test-456'
|
|
278
|
-
end
|
|
279
|
-
end
|
|
280
|
-
|
|
281
|
-
describe "#discontinue_on_must_be_later_than_available_on" do
|
|
282
|
-
before { product.available_on = Date.today }
|
|
283
|
-
|
|
284
|
-
context "available_on is a date earlier than discontinue_on" do
|
|
285
|
-
before { product.discontinue_on = 5.days.from_now }
|
|
286
|
-
|
|
287
|
-
it "is valid" do
|
|
288
|
-
expect(product).to be_valid
|
|
289
|
-
end
|
|
290
|
-
end
|
|
291
|
-
|
|
292
|
-
context "available_on is a date earlier than discontinue_on" do
|
|
293
|
-
before { product.discontinue_on = 5.days.ago }
|
|
294
|
-
|
|
295
|
-
context "is not valid" do
|
|
296
|
-
before { product.valid? }
|
|
297
|
-
|
|
298
|
-
it { expect(product).not_to be_valid }
|
|
299
|
-
it { expect(product.errors[:discontinue_on]).to include(I18n.t(:invalid_date_range, scope: 'activerecord.errors.models.spree/product.attributes.discontinue_on')) }
|
|
300
|
-
end
|
|
301
|
-
end
|
|
302
|
-
|
|
303
|
-
context "available_on and discontinue_on are nil" do
|
|
304
|
-
before do
|
|
305
|
-
product.discontinue_on = nil
|
|
306
|
-
product.available_on = nil
|
|
307
|
-
end
|
|
308
|
-
|
|
309
|
-
it "is valid" do
|
|
310
|
-
expect(product).to be_valid
|
|
311
|
-
end
|
|
312
|
-
end
|
|
313
|
-
end
|
|
314
|
-
|
|
315
|
-
context "hard deletion" do
|
|
316
|
-
it "doesnt raise ActiveRecordError error" do
|
|
317
|
-
expect { product.really_destroy! }.to_not raise_error
|
|
318
|
-
end
|
|
319
|
-
end
|
|
320
|
-
|
|
321
|
-
context 'history' do
|
|
322
|
-
before(:each) do
|
|
323
|
-
@product = create(:product)
|
|
324
|
-
end
|
|
325
|
-
|
|
326
|
-
it 'should keep the history when the product is destroyed' do
|
|
327
|
-
@product.destroy
|
|
328
|
-
|
|
329
|
-
expect(@product.slugs.with_deleted).to_not be_empty
|
|
330
|
-
end
|
|
331
|
-
|
|
332
|
-
it 'should update the history when the product is restored' do
|
|
333
|
-
@product.destroy
|
|
334
|
-
|
|
335
|
-
@product.restore(recursive: true)
|
|
336
|
-
|
|
337
|
-
latest_slug = @product.slugs.find_by slug: @product.slug
|
|
338
|
-
expect(latest_slug).to_not be_nil
|
|
339
|
-
end
|
|
340
|
-
end
|
|
341
|
-
end
|
|
342
|
-
|
|
343
|
-
context "properties" do
|
|
344
|
-
let(:product) { create(:product) }
|
|
345
|
-
|
|
346
|
-
it "should properly assign properties" do
|
|
347
|
-
product.set_property('the_prop', 'value1')
|
|
348
|
-
expect(product.property('the_prop')).to eq('value1')
|
|
349
|
-
|
|
350
|
-
product.set_property('the_prop', 'value2')
|
|
351
|
-
expect(product.property('the_prop')).to eq('value2')
|
|
352
|
-
end
|
|
353
|
-
|
|
354
|
-
it "should not create duplicate properties when set_property is called" do
|
|
355
|
-
expect {
|
|
356
|
-
product.set_property('the_prop', 'value2')
|
|
357
|
-
product.save
|
|
358
|
-
product.reload
|
|
359
|
-
}.not_to change(product.properties, :length)
|
|
360
|
-
|
|
361
|
-
expect {
|
|
362
|
-
product.set_property('the_prop_new', 'value')
|
|
363
|
-
product.save
|
|
364
|
-
product.reload
|
|
365
|
-
expect(product.property('the_prop_new')).to eq('value')
|
|
366
|
-
}.to change { product.properties.length }.by(1)
|
|
367
|
-
end
|
|
368
|
-
|
|
369
|
-
context 'optional property_presentation' do
|
|
370
|
-
subject { Spree::Property.where(name: 'foo').first.presentation }
|
|
371
|
-
let(:name) { 'foo' }
|
|
372
|
-
let(:presentation) { 'baz' }
|
|
373
|
-
|
|
374
|
-
describe 'is not used' do
|
|
375
|
-
before { product.set_property(name, 'bar') }
|
|
376
|
-
it { is_expected.to eq name }
|
|
377
|
-
end
|
|
378
|
-
|
|
379
|
-
describe 'is used' do
|
|
380
|
-
before { product.set_property(name, 'bar', presentation) }
|
|
381
|
-
it { is_expected.to eq presentation }
|
|
382
|
-
end
|
|
383
|
-
end
|
|
384
|
-
|
|
385
|
-
# Regression test for #2455
|
|
386
|
-
it "should not overwrite properties' presentation names" do
|
|
387
|
-
Spree::Property.where(name: 'foo').first_or_create!(presentation: "Foo's Presentation Name")
|
|
388
|
-
product.set_property('foo', 'value1')
|
|
389
|
-
product.set_property('bar', 'value2')
|
|
390
|
-
expect(Spree::Property.where(name: 'foo').first.presentation).to eq("Foo's Presentation Name")
|
|
391
|
-
expect(Spree::Property.where(name: 'bar').first.presentation).to eq("bar")
|
|
392
|
-
end
|
|
393
|
-
|
|
394
|
-
# Regression test for #4416
|
|
395
|
-
context "#possible_promotions" do
|
|
396
|
-
let!(:possible_promotion) { create(:promotion, advertise: true, starts_at: 1.day.ago) }
|
|
397
|
-
let!(:unadvertised_promotion) { create(:promotion, advertise: false, starts_at: 1.day.ago) }
|
|
398
|
-
let!(:inactive_promotion) { create(:promotion, advertise: true, starts_at: 1.day.since) }
|
|
399
|
-
|
|
400
|
-
before do
|
|
401
|
-
product.promotion_rules.create!(promotion: possible_promotion)
|
|
402
|
-
product.promotion_rules.create!(promotion: unadvertised_promotion)
|
|
403
|
-
product.promotion_rules.create!(promotion: inactive_promotion)
|
|
404
|
-
end
|
|
405
|
-
|
|
406
|
-
it "lists the promotion as a possible promotion" do
|
|
407
|
-
expect(product.possible_promotions).to include(possible_promotion)
|
|
408
|
-
expect(product.possible_promotions).to_not include(unadvertised_promotion)
|
|
409
|
-
expect(product.possible_promotions).to_not include(inactive_promotion)
|
|
410
|
-
end
|
|
411
|
-
end
|
|
412
|
-
end
|
|
413
|
-
|
|
414
|
-
context '#create' do
|
|
415
|
-
let!(:prototype) { create(:prototype) }
|
|
416
|
-
let!(:product) { Spree::Product.new(name: "Foo", price: 1.99, shipping_category_id: create(:shipping_category).id) }
|
|
417
|
-
|
|
418
|
-
before { product.prototype_id = prototype.id }
|
|
419
|
-
|
|
420
|
-
context "when prototype is supplied" do
|
|
421
|
-
it "should create properties based on the prototype" do
|
|
422
|
-
product.save
|
|
423
|
-
expect(product.properties.count).to eq(1)
|
|
424
|
-
end
|
|
425
|
-
end
|
|
426
|
-
|
|
427
|
-
context "when prototype with option types is supplied" do
|
|
428
|
-
def build_option_type_with_values(name, values)
|
|
429
|
-
values.each_with_object(create :option_type, name: name) do |val, ot|
|
|
430
|
-
ot.option_values.create(name: val.downcase, presentation: val)
|
|
431
|
-
end
|
|
432
|
-
end
|
|
433
|
-
|
|
434
|
-
let(:prototype) do
|
|
435
|
-
size = build_option_type_with_values("size", %w(Small Medium Large))
|
|
436
|
-
create(:prototype, name: "Size", option_types: [ size ])
|
|
437
|
-
end
|
|
438
|
-
|
|
439
|
-
let(:option_values_hash) do
|
|
440
|
-
hash = {}
|
|
441
|
-
prototype.option_types.each do |i|
|
|
442
|
-
hash[i.id.to_s] = i.option_value_ids
|
|
443
|
-
end
|
|
444
|
-
hash
|
|
445
|
-
end
|
|
446
|
-
|
|
447
|
-
it "should create option types based on the prototype" do
|
|
448
|
-
product.save
|
|
449
|
-
expect(product.option_type_ids.length).to eq(1)
|
|
450
|
-
expect(product.option_type_ids).to eq(prototype.option_type_ids)
|
|
451
|
-
end
|
|
452
|
-
|
|
453
|
-
it "should create product option types based on the prototype" do
|
|
454
|
-
product.save
|
|
455
|
-
expect(product.product_option_types.pluck(:option_type_id)).to eq(prototype.option_type_ids)
|
|
456
|
-
end
|
|
457
|
-
|
|
458
|
-
it "should create variants from an option values hash with one option type" do
|
|
459
|
-
product.option_values_hash = option_values_hash
|
|
460
|
-
product.save
|
|
461
|
-
expect(product.variants.length).to eq(3)
|
|
462
|
-
end
|
|
463
|
-
|
|
464
|
-
it "should still create variants when option_values_hash is given but prototype id is nil" do
|
|
465
|
-
product.option_values_hash = option_values_hash
|
|
466
|
-
product.prototype_id = nil
|
|
467
|
-
product.save
|
|
468
|
-
product.reload
|
|
469
|
-
expect(product.option_type_ids.length).to eq(1)
|
|
470
|
-
expect(product.option_type_ids).to eq(prototype.option_type_ids)
|
|
471
|
-
expect(product.variants.length).to eq(3)
|
|
472
|
-
end
|
|
473
|
-
|
|
474
|
-
it "should create variants from an option values hash with multiple option types" do
|
|
475
|
-
color = build_option_type_with_values("color", %w(Red Green Blue))
|
|
476
|
-
logo = build_option_type_with_values("logo", %w(Ruby Rails Nginx))
|
|
477
|
-
option_values_hash[color.id.to_s] = color.option_value_ids
|
|
478
|
-
option_values_hash[logo.id.to_s] = logo.option_value_ids
|
|
479
|
-
product.option_values_hash = option_values_hash
|
|
480
|
-
product.save
|
|
481
|
-
product.reload
|
|
482
|
-
expect(product.option_type_ids.length).to eq(3)
|
|
483
|
-
expect(product.variants.length).to eq(27)
|
|
484
|
-
end
|
|
485
|
-
end
|
|
486
|
-
end
|
|
487
|
-
|
|
488
|
-
context "#images" do
|
|
489
|
-
let(:product) { create(:product) }
|
|
490
|
-
let(:image) { File.open(File.expand_path('../../../fixtures/thinking-cat.jpg', __FILE__)) }
|
|
491
|
-
let(:params) { {viewable_id: product.master.id, viewable_type: 'Spree::Variant', attachment: image, alt: "position 2", position: 2} }
|
|
492
|
-
|
|
493
|
-
before do
|
|
494
|
-
Spree::Image.create(params)
|
|
495
|
-
Spree::Image.create(params.merge({alt: "position 1", position: 1}))
|
|
496
|
-
Spree::Image.create(params.merge({viewable_type: 'ThirdParty::Extension', alt: "position 1", position: 2}))
|
|
497
|
-
end
|
|
498
|
-
|
|
499
|
-
it "only looks for variant images" do
|
|
500
|
-
expect(product.images.size).to eq(2)
|
|
501
|
-
end
|
|
502
|
-
|
|
503
|
-
it "should be sorted by position" do
|
|
504
|
-
expect(product.images.pluck(:alt)).to eq(["position 1", "position 2"])
|
|
505
|
-
end
|
|
506
|
-
end
|
|
507
|
-
|
|
508
|
-
# Regression tests for #2352
|
|
509
|
-
context "classifications and taxons" do
|
|
510
|
-
it "is joined through classifications" do
|
|
511
|
-
reflection = Spree::Product.reflect_on_association(:taxons)
|
|
512
|
-
expect(reflection.options[:through]).to eq(:classifications)
|
|
513
|
-
end
|
|
514
|
-
|
|
515
|
-
it "will delete all classifications" do
|
|
516
|
-
reflection = Spree::Product.reflect_on_association(:classifications)
|
|
517
|
-
expect(reflection.options[:dependent]).to eq(:delete_all)
|
|
518
|
-
end
|
|
519
|
-
end
|
|
520
|
-
|
|
521
|
-
context '#total_on_hand' do
|
|
522
|
-
let(:product) { create(:product) }
|
|
523
|
-
|
|
524
|
-
it 'should be infinite if track_inventory_levels is false' do
|
|
525
|
-
Spree::Config[:track_inventory_levels] = false
|
|
526
|
-
expect(build(:product, variants_including_master: [build(:master_variant)]).total_on_hand).to eql(Float::INFINITY)
|
|
527
|
-
end
|
|
528
|
-
|
|
529
|
-
it 'should be infinite if variant is on demand' do
|
|
530
|
-
Spree::Config[:track_inventory_levels] = true
|
|
531
|
-
expect(build(:product, variants_including_master: [build(:on_demand_master_variant)]).total_on_hand).to eql(Float::INFINITY)
|
|
532
|
-
end
|
|
533
|
-
|
|
534
|
-
it 'should return sum of stock items count_on_hand' do
|
|
535
|
-
product.stock_items.first.set_count_on_hand 5
|
|
536
|
-
product.variants_including_master.reload # force load association
|
|
537
|
-
expect(product.total_on_hand).to eql(5)
|
|
538
|
-
end
|
|
539
|
-
|
|
540
|
-
it 'should return sum of stock items count_on_hand when variants_including_master is not loaded' do
|
|
541
|
-
product.stock_items.first.set_count_on_hand 5
|
|
542
|
-
expect(product.reload.total_on_hand).to eql(5)
|
|
543
|
-
end
|
|
544
|
-
end
|
|
545
|
-
|
|
546
|
-
# Regression spec for https://github.com/spree/spree/issues/5588
|
|
547
|
-
context '#validate_master when duplicate SKUs entered' do
|
|
548
|
-
let!(:first_product) { create(:product, sku: 'a-sku') }
|
|
549
|
-
let(:second_product) { build(:product, sku: 'a-sku') }
|
|
550
|
-
|
|
551
|
-
subject { second_product }
|
|
552
|
-
it { is_expected.to be_invalid }
|
|
553
|
-
end
|
|
554
|
-
|
|
555
|
-
it "initializes a master variant when building a product" do
|
|
556
|
-
product = Spree::Product.new
|
|
557
|
-
expect(product.master.is_master).to be true
|
|
558
|
-
end
|
|
559
|
-
|
|
560
|
-
context "#discontinue!" do
|
|
561
|
-
let(:product) { create(:product, sku: 'a-sku') }
|
|
562
|
-
|
|
563
|
-
it "sets the discontinued" do
|
|
564
|
-
product.discontinue!
|
|
565
|
-
product.reload
|
|
566
|
-
expect(product.discontinued?).to be(true)
|
|
567
|
-
end
|
|
568
|
-
|
|
569
|
-
it "changes updated_at" do
|
|
570
|
-
Timecop.scale(1000) do
|
|
571
|
-
expect { product.discontinue! }.to change { product.updated_at }
|
|
572
|
-
end
|
|
573
|
-
end
|
|
574
|
-
end
|
|
575
|
-
|
|
576
|
-
context "#discontinued?" do
|
|
577
|
-
let(:product_live) { build(:product, sku: "a-sku") }
|
|
578
|
-
it "should be false" do
|
|
579
|
-
expect(product_live.discontinued?).to be(false)
|
|
580
|
-
end
|
|
581
|
-
|
|
582
|
-
let(:product_discontinued) { build(:product, sku: "a-sku", discontinue_on: Time.now - 1.day) }
|
|
583
|
-
it "should be true" do
|
|
584
|
-
expect(product_discontinued.discontinued?).to be(true)
|
|
585
|
-
end
|
|
586
|
-
end
|
|
587
|
-
|
|
588
|
-
context "acts_as_taggable" do
|
|
589
|
-
let(:product) { create(:product) }
|
|
590
|
-
|
|
591
|
-
it "should add tags" do
|
|
592
|
-
product.tag_list.add("awesome")
|
|
593
|
-
expect(product.tag_list).to include("awesome")
|
|
594
|
-
end
|
|
595
|
-
|
|
596
|
-
it "should remove tags" do
|
|
597
|
-
product.tag_list.remove("awesome")
|
|
598
|
-
expect(product.tag_list).to_not include("awesome")
|
|
599
|
-
end
|
|
600
|
-
end
|
|
601
|
-
|
|
602
|
-
context "#brand" do
|
|
603
|
-
let(:taxonomy) { create(:taxonomy, name: I18n.t('spree.taxonomy_brands_name')) }
|
|
604
|
-
let(:product) { create(:product, taxons: [taxonomy.taxons.first]) }
|
|
605
|
-
|
|
606
|
-
it 'should fetch Brand Taxon' do
|
|
607
|
-
expect(product.brand).to eql(taxonomy.taxons.first)
|
|
608
|
-
end
|
|
609
|
-
end
|
|
610
|
-
|
|
611
|
-
context "#category" do
|
|
612
|
-
let(:taxonomy) { create(:taxonomy, name: I18n.t('spree.taxonomy_categories_name')) }
|
|
613
|
-
let(:product) { create(:product, taxons: [taxonomy.taxons.first]) }
|
|
614
|
-
|
|
615
|
-
it 'should fetch Category Taxon' do
|
|
616
|
-
expect(product.category).to eql(taxonomy.taxons.first)
|
|
617
|
-
end
|
|
618
|
-
end
|
|
619
|
-
|
|
620
|
-
describe '#ensure_no_line_items' do
|
|
621
|
-
let(:product) { create(:product) }
|
|
622
|
-
let!(:line_item) { create(:line_item, variant: product.master) }
|
|
623
|
-
|
|
624
|
-
it 'should add error on product destroy' do
|
|
625
|
-
expect(product.destroy).to eq false
|
|
626
|
-
expect(product.errors[:base]).to include Spree.t(:cannot_destroy_if_attached_to_line_items)
|
|
627
|
-
end
|
|
628
|
-
end
|
|
629
|
-
end
|