solidus_core 1.0.2 → 1.0.3

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 (216) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1 -0
  3. data/Gemfile +3 -0
  4. data/Rakefile +16 -0
  5. data/script/rails +9 -0
  6. data/solidus_core.gemspec +48 -0
  7. data/spec/fixtures/thinking-cat.jpg +0 -0
  8. data/spec/helpers/base_helper_spec.rb +173 -0
  9. data/spec/helpers/order_helper_spec.rb +12 -0
  10. data/spec/helpers/products_helper_spec.rb +220 -0
  11. data/spec/helpers/taxons_helper_spec.rb +17 -0
  12. data/spec/lib/calculated_adjustments_spec.rb +7 -0
  13. data/spec/lib/i18n_spec.rb +123 -0
  14. data/spec/lib/search/base_spec.rb +86 -0
  15. data/spec/lib/search/variant_spec.rb +92 -0
  16. data/spec/lib/spree/core/controller_helpers/auth_spec.rb +66 -0
  17. data/spec/lib/spree/core/controller_helpers/order_spec.rb +92 -0
  18. data/spec/lib/spree/core/controller_helpers/search_spec.rb +17 -0
  19. data/spec/lib/spree/core/controller_helpers/store_spec.rb +16 -0
  20. data/spec/lib/spree/core/controller_helpers/strong_parameters_spec.rb +39 -0
  21. data/spec/lib/spree/core/current_store_spec.rb +36 -0
  22. data/spec/lib/spree/core/delegate_belongs_to_spec.rb +22 -0
  23. data/spec/lib/spree/core/importer/order_spec.rb +431 -0
  24. data/spec/lib/spree/core/role_configuration_spec.rb +138 -0
  25. data/spec/lib/spree/core/validators/email_spec.rb +48 -0
  26. data/spec/lib/spree/localized_number_spec.rb +38 -0
  27. data/spec/lib/spree/migrations_spec.rb +36 -0
  28. data/spec/lib/spree/money_spec.rb +127 -0
  29. data/spec/lib/tasks/exchanges_spec.rb +231 -0
  30. data/spec/lib/tasks/migrations/copy_shipped_shipments_to_cartons_spec.rb +115 -0
  31. data/spec/lib/tasks/order_capturing_spec.rb +56 -0
  32. data/spec/mailers/carton_mailer_spec.rb +43 -0
  33. data/spec/mailers/order_mailer_spec.rb +122 -0
  34. data/spec/mailers/reimbursement_mailer_spec.rb +40 -0
  35. data/spec/mailers/test_mailer_spec.rb +15 -0
  36. data/spec/models/spree/ability_spec.rb +276 -0
  37. data/spec/models/spree/address_spec.rb +250 -0
  38. data/spec/models/spree/adjustment_reason_spec.rb +13 -0
  39. data/spec/models/spree/adjustment_spec.rb +177 -0
  40. data/spec/models/spree/app_configuration_spec.rb +20 -0
  41. data/spec/models/spree/asset_spec.rb +24 -0
  42. data/spec/models/spree/calculator/default_tax_spec.rb +127 -0
  43. data/spec/models/spree/calculator/flat_percent_item_total_spec.rb +25 -0
  44. data/spec/models/spree/calculator/flat_rate_spec.rb +47 -0
  45. data/spec/models/spree/calculator/flexi_rate_spec.rb +41 -0
  46. data/spec/models/spree/calculator/percent_on_line_item_spec.rb +15 -0
  47. data/spec/models/spree/calculator/price_sack_spec.rb +30 -0
  48. data/spec/models/spree/calculator/refunds/default_refund_amount_spec.rb +51 -0
  49. data/spec/models/spree/calculator/shipping/flat_percent_item_total_spec.rb +23 -0
  50. data/spec/models/spree/calculator/shipping/flat_rate_spec.rb +13 -0
  51. data/spec/models/spree/calculator/shipping/flexi_rate_spec.rb +52 -0
  52. data/spec/models/spree/calculator/shipping/per_item_spec.rb +20 -0
  53. data/spec/models/spree/calculator/shipping/price_sack_spec.rb +30 -0
  54. data/spec/models/spree/calculator/tiered_flat_rate_spec.rb +36 -0
  55. data/spec/models/spree/calculator/tiered_percent_spec.rb +47 -0
  56. data/spec/models/spree/calculator_spec.rb +36 -0
  57. data/spec/models/spree/carton_spec.rb +133 -0
  58. data/spec/models/spree/classification_spec.rb +15 -0
  59. data/spec/models/spree/concerns/display_money_spec.rb +43 -0
  60. data/spec/models/spree/concerns/user_methods_spec.rb +41 -0
  61. data/spec/models/spree/credit_card_spec.rb +334 -0
  62. data/spec/models/spree/customer_return_spec.rb +276 -0
  63. data/spec/models/spree/exchange_spec.rb +79 -0
  64. data/spec/models/spree/gateway/bogus_simple.rb +20 -0
  65. data/spec/models/spree/gateway/bogus_spec.rb +13 -0
  66. data/spec/models/spree/gateway_spec.rb +82 -0
  67. data/spec/models/spree/inventory_unit_spec.rb +307 -0
  68. data/spec/models/spree/item_adjustments_spec.rb +256 -0
  69. data/spec/models/spree/line_item_spec.rb +191 -0
  70. data/spec/models/spree/option_type_spec.rb +14 -0
  71. data/spec/models/spree/option_value_spec.rb +22 -0
  72. data/spec/models/spree/order/address_spec.rb +50 -0
  73. data/spec/models/spree/order/adjustments_spec.rb +39 -0
  74. data/spec/models/spree/order/callbacks_spec.rb +42 -0
  75. data/spec/models/spree/order/checkout_spec.rb +902 -0
  76. data/spec/models/spree/order/currency_updater_spec.rb +32 -0
  77. data/spec/models/spree/order/finalizing_spec.rb +111 -0
  78. data/spec/models/spree/order/payment_spec.rb +210 -0
  79. data/spec/models/spree/order/risk_assessment_spec.rb +68 -0
  80. data/spec/models/spree/order/state_machine_spec.rb +221 -0
  81. data/spec/models/spree/order/tax_spec.rb +84 -0
  82. data/spec/models/spree/order/totals_spec.rb +24 -0
  83. data/spec/models/spree/order/updating_spec.rb +18 -0
  84. data/spec/models/spree/order/validations_spec.rb +15 -0
  85. data/spec/models/spree/order_cancellations_spec.rb +120 -0
  86. data/spec/models/spree/order_capturing_spec.rb +116 -0
  87. data/spec/models/spree/order_contents_spec.rb +265 -0
  88. data/spec/models/spree/order_inventory_spec.rb +228 -0
  89. data/spec/models/spree/order_mutex_spec.rb +85 -0
  90. data/spec/models/spree/order_promotion_spec.rb +31 -0
  91. data/spec/models/spree/order_shipping_spec.rb +247 -0
  92. data/spec/models/spree/order_spec.rb +1412 -0
  93. data/spec/models/spree/order_stock_location_spec.rb +18 -0
  94. data/spec/models/spree/order_updater_spec.rb +299 -0
  95. data/spec/models/spree/payment_method/store_credit_spec.rb +294 -0
  96. data/spec/models/spree/payment_method_spec.rb +96 -0
  97. data/spec/models/spree/payment_spec.rb +1044 -0
  98. data/spec/models/spree/permission_sets/base_spec.rb +12 -0
  99. data/spec/models/spree/permission_sets/configuration_display.rb +82 -0
  100. data/spec/models/spree/permission_sets/configuration_management_spec.rb +50 -0
  101. data/spec/models/spree/permission_sets/dashboard_display_spec.rb +22 -0
  102. data/spec/models/spree/permission_sets/order_display_spec.rb +49 -0
  103. data/spec/models/spree/permission_sets/order_management_spec.rb +36 -0
  104. data/spec/models/spree/permission_sets/product_display_spec.rb +60 -0
  105. data/spec/models/spree/permission_sets/product_management_spec.rb +40 -0
  106. data/spec/models/spree/permission_sets/promotion_display_spec.rb +34 -0
  107. data/spec/models/spree/permission_sets/promotion_management_spec.rb +26 -0
  108. data/spec/models/spree/permission_sets/report_display_spec.rb +24 -0
  109. data/spec/models/spree/permission_sets/restricted_transfer_management_spec.rb +132 -0
  110. data/spec/models/spree/permission_sets/stock_display_spec.rb +26 -0
  111. data/spec/models/spree/permission_sets/stock_management_spec.rb +24 -0
  112. data/spec/models/spree/permission_sets/user_display_spec.rb +36 -0
  113. data/spec/models/spree/permission_sets/user_management_spec.rb +28 -0
  114. data/spec/models/spree/preference_spec.rb +80 -0
  115. data/spec/models/spree/preferences/configuration_spec.rb +30 -0
  116. data/spec/models/spree/preferences/preferable_spec.rb +294 -0
  117. data/spec/models/spree/preferences/scoped_store_spec.rb +58 -0
  118. data/spec/models/spree/preferences/static_model_preferences_spec.rb +78 -0
  119. data/spec/models/spree/preferences/statically_configurable_spec.rb +60 -0
  120. data/spec/models/spree/preferences/store_spec.rb +39 -0
  121. data/spec/models/spree/price_spec.rb +42 -0
  122. data/spec/models/spree/product/scopes_spec.rb +148 -0
  123. data/spec/models/spree/product_duplicator_spec.rb +103 -0
  124. data/spec/models/spree/product_filter_spec.rb +26 -0
  125. data/spec/models/spree/product_property_spec.rb +20 -0
  126. data/spec/models/spree/product_spec.rb +437 -0
  127. data/spec/models/spree/promotion/actions/create_adjustment_spec.rb +96 -0
  128. data/spec/models/spree/promotion/actions/create_item_adjustments_spec.rb +165 -0
  129. data/spec/models/spree/promotion/actions/create_quantity_adjustments_spec.rb +115 -0
  130. data/spec/models/spree/promotion/actions/free_shipping_spec.rb +40 -0
  131. data/spec/models/spree/promotion/rules/first_order_spec.rb +75 -0
  132. data/spec/models/spree/promotion/rules/item_total_spec.rb +67 -0
  133. data/spec/models/spree/promotion/rules/nth_order_spec.rb +70 -0
  134. data/spec/models/spree/promotion/rules/one_use_per_user_spec.rb +42 -0
  135. data/spec/models/spree/promotion/rules/option_value_spec.rb +94 -0
  136. data/spec/models/spree/promotion/rules/product_spec.rb +143 -0
  137. data/spec/models/spree/promotion/rules/taxon_spec.rb +102 -0
  138. data/spec/models/spree/promotion/rules/user_logged_in_spec.rb +27 -0
  139. data/spec/models/spree/promotion/rules/user_spec.rb +37 -0
  140. data/spec/models/spree/promotion_builder_spec.rb +118 -0
  141. data/spec/models/spree/promotion_category_spec.rb +17 -0
  142. data/spec/models/spree/promotion_code/code_builder_spec.rb +79 -0
  143. data/spec/models/spree/promotion_code_spec.rb +187 -0
  144. data/spec/models/spree/promotion_handler/cart_spec.rb +114 -0
  145. data/spec/models/spree/promotion_handler/coupon_spec.rb +335 -0
  146. data/spec/models/spree/promotion_handler/free_shipping_spec.rb +47 -0
  147. data/spec/models/spree/promotion_handler/page_spec.rb +44 -0
  148. data/spec/models/spree/promotion_rule_spec.rb +28 -0
  149. data/spec/models/spree/promotion_spec.rb +767 -0
  150. data/spec/models/spree/refund_spec.rb +204 -0
  151. data/spec/models/spree/reimbursement/credit_spec.rb +36 -0
  152. data/spec/models/spree/reimbursement/reimbursement_type_engine_spec.rb +140 -0
  153. data/spec/models/spree/reimbursement/reimbursement_type_validator_spec.rb +83 -0
  154. data/spec/models/spree/reimbursement_performer_spec.rb +30 -0
  155. data/spec/models/spree/reimbursement_spec.rb +231 -0
  156. data/spec/models/spree/reimbursement_tax_calculator_spec.rb +51 -0
  157. data/spec/models/spree/reimbursement_type/credit_spec.rb +53 -0
  158. data/spec/models/spree/reimbursement_type/exchange_spec.rb +46 -0
  159. data/spec/models/spree/reimbursement_type/original_payment_spec.rb +107 -0
  160. data/spec/models/spree/reimbursement_type/store_credit_spec.rb +97 -0
  161. data/spec/models/spree/return_authorization_spec.rb +290 -0
  162. data/spec/models/spree/return_item/eligibility_validator/default_spec.rb +77 -0
  163. data/spec/models/spree/return_item/eligibility_validator/inventory_shipped_spec.rb +58 -0
  164. data/spec/models/spree/return_item/eligibility_validator/no_reimbursements_spec.rb +85 -0
  165. data/spec/models/spree/return_item/eligibility_validator/order_completed_spec.rb +32 -0
  166. data/spec/models/spree/return_item/eligibility_validator/rma_required_spec.rb +29 -0
  167. data/spec/models/spree/return_item/eligibility_validator/time_since_purchase_spec.rb +35 -0
  168. data/spec/models/spree/return_item/exchange_variant_eligibility/same_option_value_spec.rb +65 -0
  169. data/spec/models/spree/return_item/exchange_variant_eligibility/same_product_spec.rb +43 -0
  170. data/spec/models/spree/return_item_spec.rb +775 -0
  171. data/spec/models/spree/returns_calculator_spec.rb +14 -0
  172. data/spec/models/spree/shipment_spec.rb +709 -0
  173. data/spec/models/spree/shipping_calculator_spec.rb +45 -0
  174. data/spec/models/spree/shipping_method_spec.rb +88 -0
  175. data/spec/models/spree/shipping_rate_spec.rb +142 -0
  176. data/spec/models/spree/state_spec.rb +14 -0
  177. data/spec/models/spree/stock/availability_validator_spec.rb +83 -0
  178. data/spec/models/spree/stock/coordinator_spec.rb +116 -0
  179. data/spec/models/spree/stock/differentiator_spec.rb +39 -0
  180. data/spec/models/spree/stock/estimator_spec.rb +146 -0
  181. data/spec/models/spree/stock/inventory_unit_builder_spec.rb +38 -0
  182. data/spec/models/spree/stock/package_spec.rb +163 -0
  183. data/spec/models/spree/stock/packer_spec.rb +91 -0
  184. data/spec/models/spree/stock/prioritizer_spec.rb +125 -0
  185. data/spec/models/spree/stock/quantifier_spec.rb +115 -0
  186. data/spec/models/spree/stock/splitter/backordered_spec.rb +29 -0
  187. data/spec/models/spree/stock/splitter/base_spec.rb +21 -0
  188. data/spec/models/spree/stock/splitter/shipping_category_spec.rb +50 -0
  189. data/spec/models/spree/stock/splitter/weight_spec.rb +29 -0
  190. data/spec/models/spree/stock_item_spec.rb +426 -0
  191. data/spec/models/spree/stock_location_spec.rb +279 -0
  192. data/spec/models/spree/stock_movement_spec.rb +56 -0
  193. data/spec/models/spree/stock_transfer_spec.rb +290 -0
  194. data/spec/models/spree/store_credit_category_spec.rb +17 -0
  195. data/spec/models/spree/store_credit_event_spec.rb +314 -0
  196. data/spec/models/spree/store_credit_spec.rb +876 -0
  197. data/spec/models/spree/store_spec.rb +55 -0
  198. data/spec/models/spree/tax_category_spec.rb +27 -0
  199. data/spec/models/spree/tax_rate_spec.rb +378 -0
  200. data/spec/models/spree/taxon_spec.rb +74 -0
  201. data/spec/models/spree/taxonomy_spec.rb +18 -0
  202. data/spec/models/spree/tracker_spec.rb +21 -0
  203. data/spec/models/spree/transfer_item_spec.rb +264 -0
  204. data/spec/models/spree/unit_cancel_spec.rb +148 -0
  205. data/spec/models/spree/user_spec.rb +223 -0
  206. data/spec/models/spree/validations/db_maximum_length_validator_spec.rb +23 -0
  207. data/spec/models/spree/variant/scopes_spec.rb +55 -0
  208. data/spec/models/spree/variant_spec.rb +546 -0
  209. data/spec/models/spree/zone_spec.rb +305 -0
  210. data/spec/spec_helper.rb +78 -0
  211. data/spec/support/big_decimal.rb +5 -0
  212. data/spec/support/concerns/default_price.rb +34 -0
  213. data/spec/support/dummy_ability.rb +4 -0
  214. data/spec/support/test_gateway.rb +2 -0
  215. metadata +229 -3
  216. data/lib/spree/testing_support/rspec-activemodel-mocks_patch.rb +0 -8
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ module Stock
5
+ describe Differentiator, :type => :model do
6
+ let(:variant1) { mock_model(Variant) }
7
+ let(:variant2) { mock_model(Variant) }
8
+
9
+ let(:line_item1) { build(:line_item, variant: variant1, quantity: 2) }
10
+ let(:line_item2) { build(:line_item, variant: variant2, quantity: 2) }
11
+
12
+ let(:stock_location) { mock_model(StockLocation) }
13
+
14
+ let(:inventory_unit1) { build(:inventory_unit, variant: variant1, line_item: line_item1) }
15
+ let(:inventory_unit2) { build(:inventory_unit, variant: variant2, line_item: line_item2) }
16
+
17
+ let(:order) { mock_model(Order, line_items: [line_item1, line_item2]) }
18
+
19
+ let(:package1) do
20
+ Package.new(stock_location).tap { |p| p.add(inventory_unit1) }
21
+ end
22
+
23
+ let(:package2) do
24
+ Package.new(stock_location).tap { |p| p.add(inventory_unit2) }
25
+ end
26
+
27
+ let(:packages) { [package1, package2] }
28
+
29
+ subject { Differentiator.new(order, packages) }
30
+
31
+ it { is_expected.to be_missing }
32
+
33
+ it 'calculates the missing items' do
34
+ expect(subject.missing[variant1]).to eq 1
35
+ expect(subject.missing[variant2]).to eq 1
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,146 @@
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
+ it "sorts shipping rates by cost" do
74
+ shipping_methods = 3.times.map { create(:shipping_method) }
75
+ allow(shipping_methods[0]).to receive_message_chain(:calculator, :compute).and_return(5.00)
76
+ allow(shipping_methods[1]).to receive_message_chain(:calculator, :compute).and_return(3.00)
77
+ allow(shipping_methods[2]).to receive_message_chain(:calculator, :compute).and_return(4.00)
78
+
79
+ allow(subject).to receive(:shipping_methods).and_return(shipping_methods)
80
+
81
+ expect(subject.shipping_rates(package).map(&:cost)).to eq %w[3.00 4.00 5.00].map(&BigDecimal.method(:new))
82
+ end
83
+
84
+ context "general shipping methods" do
85
+ let(:shipping_methods) { 2.times.map { create(:shipping_method) } }
86
+
87
+ it "selects the most affordable shipping rate" do
88
+ allow(shipping_methods[0]).to receive_message_chain(:calculator, :compute).and_return(5.00)
89
+ allow(shipping_methods[1]).to receive_message_chain(:calculator, :compute).and_return(3.00)
90
+
91
+ allow(subject).to receive(:shipping_methods).and_return(shipping_methods)
92
+
93
+ expect(subject.shipping_rates(package).sort_by(&:cost).map(&:selected)).to eq [true, false]
94
+ end
95
+
96
+ it "selects the most affordable shipping rate and doesn't raise exception over nil cost" do
97
+ allow(shipping_methods[0]).to receive_message_chain(:calculator, :compute).and_return(1.00)
98
+ allow(shipping_methods[1]).to receive_message_chain(:calculator, :compute).and_return(nil)
99
+
100
+ allow(subject).to receive(:shipping_methods).and_return(shipping_methods)
101
+
102
+ subject.shipping_rates(package)
103
+ end
104
+ end
105
+
106
+ context "involves backend only shipping methods" do
107
+ let(:backend_method) { create(:shipping_method, display_on: "back_end") }
108
+ let(:generic_method) { create(:shipping_method) }
109
+
110
+ before do
111
+ allow(backend_method).to receive_message_chain(:calculator, :compute).and_return(0.00)
112
+ allow(generic_method).to receive_message_chain(:calculator, :compute).and_return(5.00)
113
+ allow(subject).to receive(:shipping_methods).and_return([backend_method, generic_method])
114
+ end
115
+
116
+ it "does not return backend rates at all" do
117
+ expect(subject.shipping_rates(package).map(&:shipping_method_id)).to eq([generic_method.id])
118
+ end
119
+
120
+ # regression for #3287
121
+ it "doesn't select backend rates even if they're more affordable" do
122
+ expect(subject.shipping_rates(package).map(&:selected)).to eq [true]
123
+ end
124
+ end
125
+
126
+ context "includes tax adjustments if applicable" do
127
+ let!(:tax_rate) { create(:tax_rate, zone: order.tax_zone) }
128
+
129
+ before do
130
+ Spree::ShippingMethod.all.each do |sm|
131
+ sm.tax_category_id = tax_rate.tax_category_id
132
+ sm.save
133
+ end
134
+ package.shipping_methods.map(&:reload)
135
+ end
136
+
137
+
138
+ it "links the shipping rate and the tax rate" do
139
+ shipping_rates = subject.shipping_rates(package)
140
+ expect(shipping_rates.first.tax_rate).to eq(tax_rate)
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
146
+ 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,163 @@
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
+ it 'filters by on_hand and backordered' do
22
+ 4.times { subject.add build_inventory_unit }
23
+ 3.times { subject.add build_inventory_unit, :backordered }
24
+ expect(subject.on_hand.count).to eq 4
25
+ expect(subject.backordered.count).to eq 3
26
+ end
27
+
28
+ it 'calculates the quantity by state' do
29
+ 4.times { subject.add build_inventory_unit }
30
+ 3.times { subject.add build_inventory_unit, :backordered }
31
+
32
+ expect(subject.quantity).to eq 7
33
+ expect(subject.quantity(:on_hand)).to eq 4
34
+ expect(subject.quantity(:backordered)).to eq 3
35
+ end
36
+
37
+ it 'returns nil for content item not found' do
38
+ unit = build_inventory_unit
39
+ item = subject.find_item(unit, :on_hand)
40
+ expect(item).to be_nil
41
+ end
42
+
43
+ it 'finds content item for an inventory unit' do
44
+ unit = build_inventory_unit
45
+ subject.add unit
46
+ item = subject.find_item(unit, :on_hand)
47
+ expect(item.quantity).to eq 1
48
+ end
49
+
50
+ # Contains regression test for #2804
51
+ it 'builds a list of shipping methods common to all categories' do
52
+ category1 = create(:shipping_category)
53
+ category2 = create(:shipping_category)
54
+ method1 = create(:shipping_method)
55
+ method2 = create(:shipping_method)
56
+ method1.shipping_categories = [category1, category2]
57
+ method2.shipping_categories = [category1]
58
+ variant1 = mock_model(Variant, shipping_category: category1)
59
+ variant2 = mock_model(Variant, shipping_category: category2)
60
+ variant3 = mock_model(Variant, shipping_category: nil)
61
+ contents = [ContentItem.new(build(:inventory_unit, variant: variant1)),
62
+ ContentItem.new(build(:inventory_unit, variant: variant1)),
63
+ ContentItem.new(build(:inventory_unit, variant: variant2)),
64
+ ContentItem.new(build(:inventory_unit, variant: variant3))]
65
+
66
+ package = Package.new(stock_location, contents)
67
+ expect(package.shipping_methods).to eq([method1])
68
+ end
69
+
70
+ it 'builds an empty list of shipping methods when no categories' do
71
+ variant = mock_model(Variant, shipping_category: nil)
72
+ contents = [ContentItem.new(build(:inventory_unit, variant: variant))]
73
+ package = Package.new(stock_location, contents)
74
+ expect(package.shipping_methods).to be_empty
75
+ end
76
+
77
+ it "can convert to a shipment" do
78
+ 2.times { subject.add build_inventory_unit }
79
+ subject.add build_inventory_unit, :backordered
80
+
81
+ shipping_method = build(:shipping_method)
82
+ subject.shipping_rates = [ Spree::ShippingRate.new(shipping_method: shipping_method, cost: 10.00, selected: true) ]
83
+
84
+ shipment = subject.to_shipment
85
+ expect(shipment.stock_location).to eq subject.stock_location
86
+ expect(shipment.inventory_units.size).to eq 3
87
+
88
+ first_unit = shipment.inventory_units.first
89
+ expect(first_unit.variant).to eq variant
90
+ expect(first_unit.state).to eq 'on_hand'
91
+ expect(first_unit).to be_pending
92
+
93
+ last_unit = shipment.inventory_units.last
94
+ expect(last_unit.variant).to eq variant
95
+ expect(last_unit.state).to eq 'backordered'
96
+
97
+ expect(shipment.shipping_method).to eq shipping_method
98
+ end
99
+
100
+ it 'does not add an inventory unit to a package twice' do
101
+ # since inventory units currently don't have a quantity
102
+ unit = build_inventory_unit
103
+ subject.add unit
104
+ subject.add unit
105
+ expect(subject.quantity).to eq 1
106
+ expect(subject.contents.first.inventory_unit).to eq unit
107
+ expect(subject.contents.first.quantity).to eq 1
108
+ end
109
+
110
+ describe "#add_multiple" do
111
+ it "adds multiple inventory units" do
112
+ expect { subject.add_multiple [build_inventory_unit, build_inventory_unit] }.to change { subject.quantity }.by(2)
113
+ end
114
+
115
+ it "allows adding with a state" do
116
+ expect { subject.add_multiple [build_inventory_unit, build_inventory_unit], :backordered }.to change { subject.backordered.count }.by(2)
117
+ end
118
+
119
+ it "defaults to adding with the on hand state" do
120
+ expect { subject.add_multiple [build_inventory_unit, build_inventory_unit] }.to change { subject.on_hand.count }.by(2)
121
+ end
122
+ end
123
+
124
+ describe "#remove" do
125
+ let(:unit) { build_inventory_unit }
126
+ context "there is a content item for the inventory unit" do
127
+
128
+ before { subject.add unit }
129
+
130
+ it "removes that content item" do
131
+ expect { subject.remove(unit) }.to change { subject.quantity }.by(-1)
132
+ expect(subject.contents.map(&:inventory_unit)).not_to include unit
133
+ end
134
+ end
135
+
136
+ context "there is no content item for the inventory unit" do
137
+ it "doesn't change the set of content items" do
138
+ expect { subject.remove(unit) }.not_to change { subject.quantity }
139
+ end
140
+ end
141
+ end
142
+
143
+ describe "#order" do
144
+ let(:unit) { build_inventory_unit }
145
+ context "there is an inventory unit" do
146
+
147
+ before { subject.add unit }
148
+
149
+ it "returns an order" do
150
+ expect(subject.order).to be_a_kind_of Spree::Order
151
+ expect(subject.order).to eq unit.order
152
+ end
153
+ end
154
+
155
+ context "there is no inventory unit" do
156
+ it "returns nil" do
157
+ expect(subject.order).to eq nil
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ module Stock
5
+ describe Packer, :type => :model do
6
+ let!(:inventory_units) { 5.times.map { build(:inventory_unit) } }
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.size).to eq 1
15
+ expect(packages.first.contents.size).to eq 5
16
+ end
17
+
18
+ it 'allows users to set splitters to an empty array' do
19
+ packages = Packer.new(stock_location, inventory_units, []).packages
20
+ expect(packages.size).to eq 1
21
+ end
22
+ end
23
+
24
+ context 'default_package' do
25
+ it 'contains all the items' do
26
+ package = subject.default_package
27
+ expect(package.contents.size).to eq 5
28
+ end
29
+
30
+ it 'variants are added as backordered without enough on_hand' do
31
+ expect(stock_location).to receive(:fill_status).exactly(5).times.and_return(
32
+ *(Array.new(3, [1,0]) + Array.new(2, [0,1]))
33
+ )
34
+
35
+ package = subject.default_package
36
+ expect(package.on_hand.size).to eq 3
37
+ expect(package.backordered.size).to eq 2
38
+ end
39
+
40
+ context "location doesn't have order items in stock" do
41
+ let(:stock_location) { create(:stock_location, propagate_all_variants: false) }
42
+ let(:packer) { Packer.new(stock_location, inventory_units) }
43
+
44
+ it "builds an empty package" do
45
+ expect(packer.default_package.contents).to be_empty
46
+ end
47
+ end
48
+
49
+ context "not enough on hand and not backorderable" do
50
+ let(:packer) { Packer.new(stock_location, inventory_units) }
51
+
52
+ before do
53
+ stock_location.stock_items.update_all(backorderable: false)
54
+ stock_location.stock_items.each { |si| si.set_count_on_hand(0) }
55
+ end
56
+
57
+ it "raises an error" do
58
+ expect { packer.default_package }.to raise_error Spree::Order::InsufficientStock
59
+ end
60
+ end
61
+
62
+ context "doesn't track inventory levels" do
63
+ let(:variant) { build(:variant) }
64
+ let(:order) { build(:order_with_line_items, line_items_count: 1) }
65
+ let(:line_item) { order.line_items.first }
66
+ let(:inventory_units) {
67
+ 30.times.map do
68
+ build(
69
+ :inventory_unit,
70
+ order: order,
71
+ line_item: line_item,
72
+ variant: variant,
73
+ )
74
+ end
75
+ }
76
+
77
+ before { Config.track_inventory_levels = false }
78
+
79
+ it "doesn't bother stock items status in stock location" do
80
+ expect(subject.stock_location).not_to receive(:fill_status)
81
+ subject.default_package
82
+ end
83
+
84
+ it "still creates package with proper quantity" do
85
+ expect(subject.default_package.quantity).to eql 30
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end