spree_core 3.0.5 → 3.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/Gemfile +3 -0
  4. data/Rakefile +30 -0
  5. data/app/assets/javascripts/spree.js.coffee.erb +1 -1
  6. data/app/models/spree/ability.rb +1 -1
  7. data/app/models/spree/base.rb +3 -1
  8. data/app/models/spree/order_updater.rb +2 -1
  9. data/app/models/spree/price.rb +7 -12
  10. data/app/models/spree/product.rb +3 -2
  11. data/app/models/spree/reimbursement.rb +1 -1
  12. data/app/models/spree/state.rb +2 -0
  13. data/app/models/spree/zone.rb +1 -1
  14. data/lib/spree/core/version.rb +1 -1
  15. data/lib/spree/testing_support/shoulda_matcher_configuration.rb +6 -0
  16. data/script/rails +9 -0
  17. data/spec/fixtures/thinking-cat.jpg +0 -0
  18. data/spec/helpers/base_helper_spec.rb +137 -0
  19. data/spec/helpers/products_helper_spec.rb +224 -0
  20. data/spec/lib/calculated_adjustments_spec.rb +7 -0
  21. data/spec/lib/i18n_spec.rb +123 -0
  22. data/spec/lib/search/base_spec.rb +86 -0
  23. data/spec/lib/spree/core/controller_helpers/auth_spec.rb +101 -0
  24. data/spec/lib/spree/core/controller_helpers/order_spec.rb +95 -0
  25. data/spec/lib/spree/core/controller_helpers/search_spec.rb +17 -0
  26. data/spec/lib/spree/core/controller_helpers/store_spec.rb +16 -0
  27. data/spec/lib/spree/core/controller_helpers/strong_parameters_spec.rb +39 -0
  28. data/spec/lib/spree/core/delegate_belongs_to_spec.rb +22 -0
  29. data/spec/lib/spree/core/importer/order_spec.rb +502 -0
  30. data/spec/lib/spree/core/validators/email_spec.rb +53 -0
  31. data/spec/lib/spree/localized_number_spec.rb +38 -0
  32. data/spec/lib/spree/migrations_spec.rb +34 -0
  33. data/spec/lib/spree/money_spec.rb +122 -0
  34. data/spec/lib/tasks/exchanges_spec.rb +136 -0
  35. data/spec/mailers/order_mailer_spec.rb +124 -0
  36. data/spec/mailers/reimbursement_mailer_spec.rb +47 -0
  37. data/spec/mailers/shipment_mailer_spec.rb +63 -0
  38. data/spec/mailers/test_mailer_spec.rb +24 -0
  39. data/spec/models/spree/ability_spec.rb +246 -0
  40. data/spec/models/spree/address_spec.rb +291 -0
  41. data/spec/models/spree/adjustable/adjustments_updater_spec.rb +286 -0
  42. data/spec/models/spree/adjustment_spec.rb +163 -0
  43. data/spec/models/spree/app_configuration_spec.rb +23 -0
  44. data/spec/models/spree/asset_spec.rb +25 -0
  45. data/spec/models/spree/calculator/default_tax_spec.rb +127 -0
  46. data/spec/models/spree/calculator/flat_percent_item_total_spec.rb +25 -0
  47. data/spec/models/spree/calculator/flat_rate_spec.rb +47 -0
  48. data/spec/models/spree/calculator/flexi_rate_spec.rb +41 -0
  49. data/spec/models/spree/calculator/percent_on_line_item_spec.rb +15 -0
  50. data/spec/models/spree/calculator/price_sack_spec.rb +30 -0
  51. data/spec/models/spree/calculator/refunds/default_refund_amount_spec.rb +51 -0
  52. data/spec/models/spree/calculator/shipping.rb +8 -0
  53. data/spec/models/spree/calculator/shipping/flat_percent_item_total_spec.rb +23 -0
  54. data/spec/models/spree/calculator/shipping/flat_rate_spec.rb +13 -0
  55. data/spec/models/spree/calculator/shipping/flexi_rate_spec.rb +52 -0
  56. data/spec/models/spree/calculator/shipping/per_item_spec.rb +20 -0
  57. data/spec/models/spree/calculator/shipping/price_sack_spec.rb +29 -0
  58. data/spec/models/spree/calculator/tiered_flat_rate_spec.rb +40 -0
  59. data/spec/models/spree/calculator/tiered_percent_spec.rb +51 -0
  60. data/spec/models/spree/calculator_spec.rb +69 -0
  61. data/spec/models/spree/classification_spec.rb +93 -0
  62. data/spec/models/spree/concerns/display_money_spec.rb +43 -0
  63. data/spec/models/spree/country_spec.rb +18 -0
  64. data/spec/models/spree/credit_card_spec.rb +324 -0
  65. data/spec/models/spree/customer_return_spec.rb +262 -0
  66. data/spec/models/spree/exchange_spec.rb +75 -0
  67. data/spec/models/spree/gateway/bogus_simple.rb +20 -0
  68. data/spec/models/spree/gateway/bogus_spec.rb +13 -0
  69. data/spec/models/spree/gateway_spec.rb +54 -0
  70. data/spec/models/spree/image_spec.rb +5 -0
  71. data/spec/models/spree/inventory_unit_spec.rb +242 -0
  72. data/spec/models/spree/line_item_spec.rb +267 -0
  73. data/spec/models/spree/option_type_spec.rb +14 -0
  74. data/spec/models/spree/option_value_spec.rb +13 -0
  75. data/spec/models/spree/order/address_spec.rb +50 -0
  76. data/spec/models/spree/order/adjustments_spec.rb +29 -0
  77. data/spec/models/spree/order/callbacks_spec.rb +42 -0
  78. data/spec/models/spree/order/checkout_spec.rb +764 -0
  79. data/spec/models/spree/order/currency_updater_spec.rb +32 -0
  80. data/spec/models/spree/order/finalizing_spec.rb +117 -0
  81. data/spec/models/spree/order/helpers_spec.rb +5 -0
  82. data/spec/models/spree/order/payment_spec.rb +214 -0
  83. data/spec/models/spree/order/risk_assessment_spec.rb +84 -0
  84. data/spec/models/spree/order/shipments_spec.rb +43 -0
  85. data/spec/models/spree/order/state_machine_spec.rb +216 -0
  86. data/spec/models/spree/order/tax_spec.rb +84 -0
  87. data/spec/models/spree/order/totals_spec.rb +24 -0
  88. data/spec/models/spree/order/updating_spec.rb +18 -0
  89. data/spec/models/spree/order/validations_spec.rb +15 -0
  90. data/spec/models/spree/order_contents_spec.rb +256 -0
  91. data/spec/models/spree/order_inventory_spec.rb +228 -0
  92. data/spec/models/spree/order_merger_spec.rb +133 -0
  93. data/spec/models/spree/order_spec.rb +954 -0
  94. data/spec/models/spree/order_updater_spec.rb +283 -0
  95. data/spec/models/spree/payment/gateway_options_spec.rb +119 -0
  96. data/spec/models/spree/payment_method_spec.rb +95 -0
  97. data/spec/models/spree/payment_spec.rb +926 -0
  98. data/spec/models/spree/preference_spec.rb +80 -0
  99. data/spec/models/spree/preferences/configuration_spec.rb +30 -0
  100. data/spec/models/spree/preferences/preferable_spec.rb +348 -0
  101. data/spec/models/spree/preferences/scoped_store_spec.rb +58 -0
  102. data/spec/models/spree/preferences/store_spec.rb +46 -0
  103. data/spec/models/spree/price_spec.rb +42 -0
  104. data/spec/models/spree/product/scopes_spec.rb +148 -0
  105. data/spec/models/spree/product_duplicator_spec.rb +103 -0
  106. data/spec/models/spree/product_filter_spec.rb +26 -0
  107. data/spec/models/spree/product_option_type_spec.rb +5 -0
  108. data/spec/models/spree/product_property_spec.rb +11 -0
  109. data/spec/models/spree/product_spec.rb +474 -0
  110. data/spec/models/spree/promotion/actions/create_adjustment_spec.rb +50 -0
  111. data/spec/models/spree/promotion/actions/create_item_adjustments_spec.rb +148 -0
  112. data/spec/models/spree/promotion/actions/create_line_items_spec.rb +86 -0
  113. data/spec/models/spree/promotion/actions/free_shipping_spec.rb +36 -0
  114. data/spec/models/spree/promotion/rules/first_order_spec.rb +75 -0
  115. data/spec/models/spree/promotion/rules/item_total_spec.rb +282 -0
  116. data/spec/models/spree/promotion/rules/one_use_per_user_spec.rb +42 -0
  117. data/spec/models/spree/promotion/rules/option_value_spec.rb +90 -0
  118. data/spec/models/spree/promotion/rules/product_spec.rb +143 -0
  119. data/spec/models/spree/promotion/rules/taxon_spec.rb +102 -0
  120. data/spec/models/spree/promotion/rules/user_logged_in_spec.rb +27 -0
  121. data/spec/models/spree/promotion/rules/user_spec.rb +37 -0
  122. data/spec/models/spree/promotion_action_spec.rb +10 -0
  123. data/spec/models/spree/promotion_category_spec.rb +17 -0
  124. data/spec/models/spree/promotion_handler/cart_spec.rb +102 -0
  125. data/spec/models/spree/promotion_handler/coupon_spec.rb +323 -0
  126. data/spec/models/spree/promotion_handler/free_shipping_spec.rb +48 -0
  127. data/spec/models/spree/promotion_handler/page_spec.rb +44 -0
  128. data/spec/models/spree/promotion_rule_spec.rb +29 -0
  129. data/spec/models/spree/promotion_spec.rb +603 -0
  130. data/spec/models/spree/property_spec.rb +5 -0
  131. data/spec/models/spree/prototype_spec.rb +5 -0
  132. data/spec/models/spree/refund_spec.rb +195 -0
  133. data/spec/models/spree/reimbursement/credit_spec.rb +36 -0
  134. data/spec/models/spree/reimbursement/reimbursement_type_engine_spec.rb +140 -0
  135. data/spec/models/spree/reimbursement/reimbursement_type_validator_spec.rb +83 -0
  136. data/spec/models/spree/reimbursement_performer_spec.rb +30 -0
  137. data/spec/models/spree/reimbursement_spec.rb +215 -0
  138. data/spec/models/spree/reimbursement_tax_calculator_spec.rb +51 -0
  139. data/spec/models/spree/reimbursement_type/credit_spec.rb +53 -0
  140. data/spec/models/spree/reimbursement_type/exchange_spec.rb +46 -0
  141. data/spec/models/spree/reimbursement_type/original_payment_spec.rb +55 -0
  142. data/spec/models/spree/return_authorization_spec.rb +250 -0
  143. data/spec/models/spree/return_item/eligibility_validator/default_spec.rb +77 -0
  144. data/spec/models/spree/return_item/eligibility_validator/inventory_shipped_spec.rb +58 -0
  145. data/spec/models/spree/return_item/eligibility_validator/no_reimbursements_spec.rb +61 -0
  146. data/spec/models/spree/return_item/eligibility_validator/order_completed_spec.rb +32 -0
  147. data/spec/models/spree/return_item/eligibility_validator/rma_required_spec.rb +29 -0
  148. data/spec/models/spree/return_item/eligibility_validator/time_since_purchase_spec.rb +35 -0
  149. data/spec/models/spree/return_item/exchange_variant_eligibility/same_option_value_spec.rb +65 -0
  150. data/spec/models/spree/return_item/exchange_variant_eligibility/same_product_spec.rb +43 -0
  151. data/spec/models/spree/return_item_spec.rb +682 -0
  152. data/spec/models/spree/returns_calculator_spec.rb +14 -0
  153. data/spec/models/spree/shipment_spec.rb +740 -0
  154. data/spec/models/spree/shipping_calculator_spec.rb +45 -0
  155. data/spec/models/spree/shipping_category_spec.rb +5 -0
  156. data/spec/models/spree/shipping_method_spec.rb +88 -0
  157. data/spec/models/spree/shipping_rate_spec.rb +141 -0
  158. data/spec/models/spree/state_spec.rb +18 -0
  159. data/spec/models/spree/stock/availability_validator_spec.rb +36 -0
  160. data/spec/models/spree/stock/content_item_spec.rb +22 -0
  161. data/spec/models/spree/stock/coordinator_spec.rb +51 -0
  162. data/spec/models/spree/stock/differentiator_spec.rb +39 -0
  163. data/spec/models/spree/stock/estimator_spec.rb +154 -0
  164. data/spec/models/spree/stock/inventory_unit_builder_spec.rb +38 -0
  165. data/spec/models/spree/stock/package_spec.rb +194 -0
  166. data/spec/models/spree/stock/packer_spec.rb +70 -0
  167. data/spec/models/spree/stock/prioritizer_spec.rb +125 -0
  168. data/spec/models/spree/stock/quantifier_spec.rb +97 -0
  169. data/spec/models/spree/stock/splitter/backordered_spec.rb +29 -0
  170. data/spec/models/spree/stock/splitter/base_spec.rb +21 -0
  171. data/spec/models/spree/stock/splitter/shipping_category_spec.rb +47 -0
  172. data/spec/models/spree/stock/splitter/weight_spec.rb +32 -0
  173. data/spec/models/spree/stock_item_spec.rb +410 -0
  174. data/spec/models/spree/stock_location_spec.rb +243 -0
  175. data/spec/models/spree/stock_movement_spec.rb +56 -0
  176. data/spec/models/spree/stock_transfer_spec.rb +50 -0
  177. data/spec/models/spree/store_spec.rb +50 -0
  178. data/spec/models/spree/tax_category_spec.rb +27 -0
  179. data/spec/models/spree/tax_rate_spec.rb +382 -0
  180. data/spec/models/spree/taxon_spec.rb +74 -0
  181. data/spec/models/spree/taxonomy_spec.rb +18 -0
  182. data/spec/models/spree/tracker_spec.rb +21 -0
  183. data/spec/models/spree/user_spec.rb +130 -0
  184. data/spec/models/spree/validations/db_maximum_length_validator_spec.rb +24 -0
  185. data/spec/models/spree/variant_spec.rb +523 -0
  186. data/spec/models/spree/zone_spec.rb +444 -0
  187. data/spec/spec_helper.rb +74 -0
  188. data/spec/support/big_decimal.rb +5 -0
  189. data/spec/support/concerns/adjustment_source_spec.rb +23 -0
  190. data/spec/support/concerns/default_price_spec.rb +28 -0
  191. data/spec/support/rake.rb +13 -0
  192. data/spec/support/test_gateway.rb +2 -0
  193. data/spree_core.gemspec +48 -0
  194. metadata +185 -4
@@ -0,0 +1,154 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ module Stock
5
+ describe Estimator, :type => :model do
6
+ let!(:shipping_method) { create(:shipping_method) }
7
+ let(:package) { build(:stock_package, contents: inventory_units.map { |i| ContentItem.new(inventory_unit) }) }
8
+ let(:order) { build(:order_with_line_items) }
9
+ let(:inventory_units) { order.inventory_units }
10
+
11
+ subject { Estimator.new(order) }
12
+
13
+ context "#shipping rates" do
14
+ before(:each) do
15
+ shipping_method.zones.first.members.create(:zoneable => order.ship_address.country)
16
+ allow_any_instance_of(ShippingMethod).to receive_message_chain(:calculator, :available?).and_return(true)
17
+ allow_any_instance_of(ShippingMethod).to receive_message_chain(:calculator, :compute).and_return(4.00)
18
+ allow_any_instance_of(ShippingMethod).to receive_message_chain(:calculator, :preferences).and_return({:currency => currency})
19
+ allow_any_instance_of(ShippingMethod).to receive_message_chain(:calculator, :marked_for_destruction?)
20
+
21
+ allow(package).to receive_messages(:shipping_methods => [shipping_method])
22
+ end
23
+
24
+ let(:currency) { "USD" }
25
+
26
+ shared_examples_for "shipping rate matches" do
27
+ it "returns shipping rates" do
28
+ shipping_rates = subject.shipping_rates(package)
29
+ expect(shipping_rates.first.cost).to eq 4.00
30
+ end
31
+ end
32
+
33
+ shared_examples_for "shipping rate doesn't match" do
34
+ it "does not return shipping rates" do
35
+ shipping_rates = subject.shipping_rates(package)
36
+ expect(shipping_rates).to eq([])
37
+ end
38
+ end
39
+
40
+ context "when the order's ship address is in the same zone" do
41
+ it_should_behave_like "shipping rate matches"
42
+ end
43
+
44
+ context "when the order's ship address is in a different zone" do
45
+ before { shipping_method.zones.each{|z| z.members.delete_all} }
46
+ it_should_behave_like "shipping rate doesn't match"
47
+ end
48
+
49
+ context "when the calculator is not available for that order" do
50
+ before { allow_any_instance_of(ShippingMethod).to receive_message_chain(:calculator, :available?).and_return(false) }
51
+ it_should_behave_like "shipping rate doesn't match"
52
+ end
53
+
54
+ context "when the currency is nil" do
55
+ let(:currency) { nil }
56
+ it_should_behave_like "shipping rate matches"
57
+ end
58
+
59
+ context "when the currency is an empty string" do
60
+ let(:currency) { "" }
61
+ it_should_behave_like "shipping rate matches"
62
+ end
63
+
64
+ context "when the current matches the order's currency" do
65
+ it_should_behave_like "shipping rate matches"
66
+ end
67
+
68
+ context "if the currency is different than the order's currency" do
69
+ let(:currency) { "GBP" }
70
+ it_should_behave_like "shipping rate doesn't match"
71
+ end
72
+
73
+ context "when the shipping method's calculator raises an exception" do
74
+ before do
75
+ allow_any_instance_of(ShippingMethod).to receive_message_chain(:calculator, :available?).and_raise(Exception, "Something went wrong!")
76
+ expect(subject).to receive(:log_calculator_exception)
77
+ end
78
+ it_should_behave_like "shipping rate doesn't match"
79
+ end
80
+
81
+ it "sorts shipping rates by cost" do
82
+ shipping_methods = 3.times.map { create(:shipping_method) }
83
+ allow(shipping_methods[0]).to receive_message_chain(:calculator, :compute).and_return(5.00)
84
+ allow(shipping_methods[1]).to receive_message_chain(:calculator, :compute).and_return(3.00)
85
+ allow(shipping_methods[2]).to receive_message_chain(:calculator, :compute).and_return(4.00)
86
+
87
+ allow(subject).to receive(:shipping_methods).and_return(shipping_methods)
88
+
89
+ expect(subject.shipping_rates(package).map(&:cost)).to eq %w[3.00 4.00 5.00].map(&BigDecimal.method(:new))
90
+ end
91
+
92
+ context "general shipping methods" do
93
+ let(:shipping_methods) { 2.times.map { create(:shipping_method) } }
94
+
95
+ it "selects the most affordable shipping rate" do
96
+ allow(shipping_methods[0]).to receive_message_chain(:calculator, :compute).and_return(5.00)
97
+ allow(shipping_methods[1]).to receive_message_chain(:calculator, :compute).and_return(3.00)
98
+
99
+ allow(subject).to receive(:shipping_methods).and_return(shipping_methods)
100
+
101
+ expect(subject.shipping_rates(package).sort_by(&:cost).map(&:selected)).to eq [true, false]
102
+ end
103
+
104
+ it "selects the most affordable shipping rate and doesn't raise exception over nil cost" do
105
+ allow(shipping_methods[0]).to receive_message_chain(:calculator, :compute).and_return(1.00)
106
+ allow(shipping_methods[1]).to receive_message_chain(:calculator, :compute).and_return(nil)
107
+
108
+ allow(subject).to receive(:shipping_methods).and_return(shipping_methods)
109
+
110
+ subject.shipping_rates(package)
111
+ end
112
+ end
113
+
114
+ context "involves backend only shipping methods" do
115
+ let(:backend_method) { create(:shipping_method, display_on: "back_end") }
116
+ let(:generic_method) { create(:shipping_method) }
117
+
118
+ before do
119
+ allow(backend_method).to receive_message_chain(:calculator, :compute).and_return(0.00)
120
+ allow(generic_method).to receive_message_chain(:calculator, :compute).and_return(5.00)
121
+ allow(package).to receive(:shipping_methods).and_return([backend_method, generic_method])
122
+ end
123
+
124
+ it "does not return backend rates at all" do
125
+ expect(subject.shipping_rates(package).map(&:shipping_method_id)).to eq([generic_method.id])
126
+ end
127
+
128
+ # regression for #3287
129
+ it "doesn't select backend rates even if they're more affordable" do
130
+ expect(subject.shipping_rates(package).map(&:selected)).to eq [true]
131
+ end
132
+ end
133
+
134
+ context "includes tax adjustments if applicable" do
135
+ let!(:tax_rate) { create(:tax_rate, zone: order.tax_zone) }
136
+
137
+ before do
138
+ Spree::ShippingMethod.all.each do |sm|
139
+ sm.tax_category_id = tax_rate.tax_category_id
140
+ sm.save
141
+ end
142
+ package.shipping_methods.map(&:reload)
143
+ end
144
+
145
+
146
+ it "links the shipping rate and the tax rate" do
147
+ shipping_rates = subject.shipping_rates(package)
148
+ expect(shipping_rates.first.tax_rate).to eq(tax_rate)
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ module Stock
5
+ describe InventoryUnitBuilder, :type => :model do
6
+ let(:line_item_1) { build(:line_item) }
7
+ let(:line_item_2) { build(:line_item, quantity: 2) }
8
+ let(:order) { build(:order, line_items: [line_item_1, line_item_2]) }
9
+
10
+ subject { InventoryUnitBuilder.new(order) }
11
+
12
+ describe "#units" do
13
+ it "returns an inventory unit for each quantity for the order's line items" do
14
+ units = subject.units
15
+ expect(units.count).to eq 3
16
+ expect(units.first.line_item).to eq line_item_1
17
+ expect(units.first.variant).to eq line_item_1.variant
18
+
19
+ expect(units[1].line_item).to eq line_item_2
20
+ expect(units[1].variant).to eq line_item_2.variant
21
+
22
+ expect(units[2].line_item).to eq line_item_2
23
+ expect(units[2].variant).to eq line_item_2.variant
24
+ end
25
+
26
+ it "builds the inventory units as pending" do
27
+ expect(subject.units.map(&:pending).uniq).to eq [true]
28
+ end
29
+
30
+ it "associates the inventory units to the order" do
31
+ expect(subject.units.map(&:order).uniq).to eq [order]
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,194 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ module Stock
5
+ describe Package, :type => :model do
6
+ let(:variant) { build(:variant, weight: 25.0) }
7
+ let(:stock_location) { build(:stock_location) }
8
+ let(:order) { build(:order) }
9
+
10
+ subject { Package.new(stock_location) }
11
+
12
+ def build_inventory_unit
13
+ build(:inventory_unit, variant: variant)
14
+ end
15
+
16
+ it 'calculates the weight of all the contents' do
17
+ 4.times { subject.add build_inventory_unit }
18
+ expect(subject.weight).to eq(100.0)
19
+ end
20
+
21
+ context "currency" do
22
+ let(:unit) { build_inventory_unit }
23
+ before { subject.add unit }
24
+
25
+ it "returns the currency based on the currency from the order" do
26
+ expect(subject.currency).to eql "USD"
27
+ end
28
+ end
29
+
30
+ it 'filters by on_hand and backordered' do
31
+ 4.times { subject.add build_inventory_unit }
32
+ 3.times { subject.add build_inventory_unit, :backordered }
33
+ expect(subject.on_hand.count).to eq 4
34
+ expect(subject.backordered.count).to eq 3
35
+ end
36
+
37
+ it 'calculates the quantity by state' do
38
+ 4.times { subject.add build_inventory_unit }
39
+ 3.times { subject.add build_inventory_unit, :backordered }
40
+
41
+ expect(subject.quantity).to eq 7
42
+ expect(subject.quantity(:on_hand)).to eq 4
43
+ expect(subject.quantity(:backordered)).to eq 3
44
+ end
45
+
46
+ it 'returns nil for content item not found' do
47
+ unit = build_inventory_unit
48
+ item = subject.find_item(unit, :on_hand)
49
+ expect(item).to be_nil
50
+ end
51
+
52
+ it 'finds content item for an inventory unit' do
53
+ unit = build_inventory_unit
54
+ subject.add unit
55
+ item = subject.find_item(unit, :on_hand)
56
+ expect(item.quantity).to eq 1
57
+ end
58
+
59
+ # Contains regression test for #2804
60
+ it 'builds a list of shipping methods common to all categories' do
61
+ category1 = create(:shipping_category)
62
+ category2 = create(:shipping_category)
63
+ method1 = create(:shipping_method)
64
+ method2 = create(:shipping_method)
65
+ method1.shipping_categories = [category1, category2]
66
+ method2.shipping_categories = [category1]
67
+ variant1 = mock_model(Variant, shipping_category: category1)
68
+ variant2 = mock_model(Variant, shipping_category: category2)
69
+ variant3 = mock_model(Variant, shipping_category: nil)
70
+ contents = [ContentItem.new(build(:inventory_unit, variant: variant1)),
71
+ ContentItem.new(build(:inventory_unit, variant: variant1)),
72
+ ContentItem.new(build(:inventory_unit, variant: variant2)),
73
+ ContentItem.new(build(:inventory_unit, variant: variant3))]
74
+
75
+ package = Package.new(stock_location, contents)
76
+ expect(package.shipping_methods).to eq([method1])
77
+ end
78
+
79
+ it 'builds an empty list of shipping methods when no categories' do
80
+ variant = mock_model(Variant, shipping_category: nil)
81
+ contents = [ContentItem.new(build(:inventory_unit, variant: variant))]
82
+ package = Package.new(stock_location, contents)
83
+ expect(package.shipping_methods).to be_empty
84
+ end
85
+
86
+ it "can convert to a shipment" do
87
+ 2.times { subject.add build_inventory_unit }
88
+ subject.add build_inventory_unit, :backordered
89
+
90
+ shipping_method = build(:shipping_method)
91
+ subject.shipping_rates = [ Spree::ShippingRate.new(shipping_method: shipping_method, cost: 10.00, selected: true) ]
92
+
93
+ shipment = subject.to_shipment
94
+ expect(shipment.stock_location).to eq subject.stock_location
95
+ expect(shipment.inventory_units.size).to eq 3
96
+
97
+ first_unit = shipment.inventory_units.first
98
+ expect(first_unit.variant).to eq variant
99
+ expect(first_unit.state).to eq 'on_hand'
100
+ expect(first_unit).to be_pending
101
+
102
+ last_unit = shipment.inventory_units.last
103
+ expect(last_unit.variant).to eq variant
104
+ expect(last_unit.state).to eq 'backordered'
105
+
106
+ expect(shipment.shipping_method).to eq shipping_method
107
+ end
108
+
109
+ it 'does not add an inventory unit to a package twice' do
110
+ # since inventory units currently don't have a quantity
111
+ unit = build_inventory_unit
112
+ subject.add unit
113
+ subject.add unit
114
+ expect(subject.quantity).to eq 1
115
+ expect(subject.contents.first.inventory_unit).to eq unit
116
+ expect(subject.contents.first.quantity).to eq 1
117
+ end
118
+
119
+ describe "#add_multiple" do
120
+ it "adds multiple inventory units" do
121
+ expect { subject.add_multiple [build_inventory_unit, build_inventory_unit] }.to change { subject.quantity }.by(2)
122
+ end
123
+
124
+ it "allows adding with a state" do
125
+ expect { subject.add_multiple [build_inventory_unit, build_inventory_unit], :backordered }.to change { subject.backordered.count }.by(2)
126
+ end
127
+
128
+ it "defaults to adding with the on hand state" do
129
+ expect { subject.add_multiple [build_inventory_unit, build_inventory_unit] }.to change { subject.on_hand.count }.by(2)
130
+ end
131
+ end
132
+
133
+ describe "#remove" do
134
+ let(:unit) { build_inventory_unit }
135
+ context "there is a content item for the inventory unit" do
136
+
137
+ before { subject.add unit }
138
+
139
+ it "removes that content item" do
140
+ expect { subject.remove(unit) }.to change { subject.quantity }.by(-1)
141
+ expect(subject.contents.map(&:inventory_unit)).not_to include unit
142
+ end
143
+ end
144
+
145
+ context "there is no content item for the inventory unit" do
146
+ it "doesn't change the set of content items" do
147
+ expect { subject.remove(unit) }.not_to change { subject.quantity }
148
+ end
149
+ end
150
+ end
151
+
152
+ describe "#order" do
153
+ let(:unit) { build_inventory_unit }
154
+ context "there is an inventory unit" do
155
+
156
+ before { subject.add unit }
157
+
158
+ it "returns an order" do
159
+ expect(subject.order).to be_a_kind_of Spree::Order
160
+ expect(subject.order).to eq unit.order
161
+ end
162
+ end
163
+
164
+ context "there is no inventory unit" do
165
+ it "returns nil" do
166
+ expect(subject.order).to eq nil
167
+ end
168
+ end
169
+ end
170
+
171
+ context "#volume" do
172
+ it "calculates the sum of the volume of all the items" do
173
+ contents = [ContentItem.new(build(:inventory_unit, variant: build(:variant))),
174
+ ContentItem.new(build(:inventory_unit, variant: build(:variant))),
175
+ ContentItem.new(build(:inventory_unit, variant: build(:variant))),
176
+ ContentItem.new(build(:inventory_unit, variant: build(:variant)))]
177
+ package = Package.new(stock_location, contents)
178
+ expect(package.volume).to eq contents.sum(&:volume)
179
+ end
180
+ end
181
+
182
+ context "#dimension" do
183
+ it "calculates the sum of the dimension of all the items" do
184
+ contents = [ContentItem.new(build(:inventory_unit, variant: build(:variant))),
185
+ ContentItem.new(build(:inventory_unit, variant: build(:variant))),
186
+ ContentItem.new(build(:inventory_unit, variant: build(:variant))),
187
+ ContentItem.new(build(:inventory_unit, variant: build(:variant)))]
188
+ package = Package.new(stock_location, contents)
189
+ expect(package.dimension).to eq contents.sum(&:dimension)
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,70 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ module Stock
5
+ describe Packer, :type => :model do
6
+ let(:inventory_units) { [InventoryUnit.new(variant: create(:variant))] }
7
+ let(:stock_location) { create(:stock_location) }
8
+
9
+ subject { Packer.new(stock_location, inventory_units) }
10
+
11
+ context 'packages' do
12
+ it 'builds an array of packages' do
13
+ packages = subject.packages
14
+ expect(packages).to be_a Array
15
+ expect(packages.first).to be_a Package
16
+ end
17
+
18
+ it 'allows users to set splitters to an empty array' do
19
+ packer = Packer.new(StockLocation.new, [], [])
20
+ expect(packer).not_to receive(:build_splitter)
21
+ packages = packer.packages
22
+ end
23
+ end
24
+
25
+ context 'default_package' do
26
+ let!(:inventory_units) { 2.times.map { InventoryUnit.new variant: create(:variant) } }
27
+
28
+ it 'contains all the items' do
29
+ package = subject.default_package
30
+ expect(package.contents.size).to eq 2
31
+ end
32
+
33
+ it 'variants are added as backordered without enough on_hand' do
34
+ expect(stock_location).to receive(:fill_status).exactly(2).times.and_return(
35
+ *(Array.new(1, [1,0]) + Array.new(1, [0,1]))
36
+ )
37
+
38
+ package = subject.default_package
39
+ expect(package.on_hand.size).to eq 1
40
+ expect(package.backordered.size).to eq 1
41
+ end
42
+
43
+ context "location doesn't have order items in stock" do
44
+ let(:stock_location) { create(:stock_location, propagate_all_variants: false) }
45
+ let(:inventory_units) { [InventoryUnit.new(variant: create(:variant))] }
46
+ let(:packer) { Packer.new(stock_location, inventory_units) }
47
+
48
+ it "builds an empty package" do
49
+ expect(packer.default_package.contents).to be_empty
50
+ end
51
+ end
52
+
53
+ context "doesn't track inventory levels" do
54
+ let(:inventory_units) { 2.times.map { InventoryUnit.new(variant: create(:variant)) } }
55
+
56
+ before { Config.track_inventory_levels = false }
57
+
58
+ it "doesn't bother stock items status in stock location" do
59
+ expect(subject.stock_location).not_to receive(:fill_status)
60
+ subject.default_package
61
+ end
62
+
63
+ it "still creates package with proper quantity" do
64
+ expect(subject.default_package.quantity).to eql 2
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end