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,14 @@
1
+ require 'spec_helper'
2
+
3
+ module Spree
4
+ describe ReturnsCalculator, :type => :model do
5
+ let(:return_item) { build(:return_item) }
6
+ subject { ReturnsCalculator.new }
7
+
8
+ it 'compute_shipment must be overridden' do
9
+ expect {
10
+ subject.compute(return_item)
11
+ }.to raise_error NotImplementedError
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,709 @@
1
+ require 'spec_helper'
2
+ require 'benchmark'
3
+
4
+ describe Spree::Shipment, :type => :model do
5
+ let(:stock_location) { create(:stock_location) }
6
+ let(:order) { create(:order_ready_to_ship, line_items_count: 1) }
7
+ let(:shipping_method) { create(:shipping_method, name: "UPS") }
8
+ let(:stock_location) { create(:stock_location) }
9
+ let(:shipment) do
10
+ order.shipments.create!(
11
+ state: 'pending',
12
+ cost: 1,
13
+ address: order.ship_address,
14
+ inventory_units: order.inventory_units,
15
+ shipping_rates: [
16
+ Spree::ShippingRate.new(
17
+ shipping_method: shipping_method,
18
+ selected: true,
19
+ ),
20
+ ],
21
+ stock_location: stock_location,
22
+ )
23
+ end
24
+
25
+ let(:variant) { mock_model(Spree::Variant) }
26
+ let(:line_item) { mock_model(Spree::LineItem, variant: variant) }
27
+
28
+ # Regression test for #4063
29
+ context "number generation" do
30
+ before do
31
+ allow(order).to receive :update!
32
+ end
33
+
34
+ it "generates a number containing a letter + 11 numbers" do
35
+ shipment.save
36
+ expect(shipment.number[0]).to eq("H")
37
+ expect(/\d{11}/.match(shipment.number)).not_to be_nil
38
+ expect(shipment.number.length).to eq(12)
39
+ end
40
+ end
41
+
42
+ it 'is backordered if one if its inventory_units is backordered' do
43
+ shipment.inventory_units = [
44
+ build(:inventory_unit, state: 'backordered', shipment: nil),
45
+ build(:inventory_unit, state: 'shipped', shipment: nil),
46
+ ]
47
+ expect(shipment).to be_backordered
48
+ end
49
+
50
+ context '#determine_state' do
51
+ it 'returns canceled if order is canceled?' do
52
+ allow(order).to receive_messages canceled?: true
53
+ expect(shipment.determine_state(order)).to eq 'canceled'
54
+ end
55
+
56
+ it 'returns pending unless order.can_ship?' do
57
+ allow(order).to receive_messages can_ship?: false
58
+ expect(shipment.determine_state(order)).to eq 'pending'
59
+ end
60
+
61
+ it 'returns pending if backordered' do
62
+ allow(shipment).to receive_messages inventory_units: [mock_model(Spree::InventoryUnit, backordered?: true)]
63
+ expect(shipment.determine_state(order)).to eq 'pending'
64
+ end
65
+
66
+ it 'returns shipped when already shipped' do
67
+ allow(shipment).to receive_messages state: 'shipped'
68
+ expect(shipment.determine_state(order)).to eq 'shipped'
69
+ end
70
+
71
+ it 'returns pending when unpaid' do
72
+ allow(order).to receive_messages paid?: false
73
+ expect(shipment.determine_state(order)).to eq 'pending'
74
+ end
75
+
76
+ it 'returns ready when paid' do
77
+ allow(order).to receive_messages paid?: true
78
+ expect(shipment.determine_state(order)).to eq 'ready'
79
+ end
80
+ end
81
+
82
+ context "display_amount" do
83
+ it "retuns a Spree::Money" do
84
+ shipment.cost = 21.22
85
+ expect(shipment.display_amount).to eq(Spree::Money.new(21.22))
86
+ end
87
+ end
88
+
89
+ context "display_final_price" do
90
+ it "retuns a Spree::Money" do
91
+ allow(shipment).to receive(:final_price) { 21.22 }
92
+ expect(shipment.display_final_price).to eq(Spree::Money.new(21.22))
93
+ end
94
+ end
95
+
96
+ context "display_item_cost" do
97
+ it "retuns a Spree::Money" do
98
+ allow(shipment).to receive(:item_cost) { 21.22 }
99
+ expect(shipment.display_item_cost).to eq(Spree::Money.new(21.22))
100
+ end
101
+ end
102
+
103
+ context "#item_cost" do
104
+ it 'should equal line items final amount with tax' do
105
+ shipment = create(:shipment, order: create(:order_with_totals))
106
+ create :tax_adjustment, adjustable: shipment.order.line_items.first, order: shipment.order
107
+ expect(shipment.item_cost).to eql(11.0)
108
+ end
109
+ end
110
+
111
+ it "#discounted_cost" do
112
+ shipment = create(:shipment)
113
+ shipment.cost = 10
114
+ shipment.promo_total = -1
115
+ expect(shipment.discounted_cost).to eq(9)
116
+ end
117
+
118
+ it "#tax_total with included taxes" do
119
+ shipment = Spree::Shipment.new
120
+ expect(shipment.tax_total).to eq(0)
121
+ shipment.included_tax_total = 10
122
+ expect(shipment.tax_total).to eq(10)
123
+ end
124
+
125
+ it "#tax_total with additional taxes" do
126
+ shipment = Spree::Shipment.new
127
+ expect(shipment.tax_total).to eq(0)
128
+ shipment.additional_tax_total = 10
129
+ expect(shipment.tax_total).to eq(10)
130
+ end
131
+
132
+ it "#final_price" do
133
+ shipment = Spree::Shipment.new
134
+ shipment.cost = 10
135
+ shipment.adjustment_total = -2
136
+ shipment.included_tax_total = 1
137
+ expect(shipment.final_price).to eq(8)
138
+ end
139
+
140
+ context "manifest" do
141
+ let(:order) { Spree::Order.create }
142
+ let(:variant) { create(:variant) }
143
+ let!(:line_item) { order.contents.add variant }
144
+ let!(:shipment) { order.create_proposed_shipments.first }
145
+
146
+ it "returns variant expected" do
147
+ expect(shipment.manifest.first.variant).to eq variant
148
+ end
149
+
150
+ context "variant was removed" do
151
+ before { variant.destroy }
152
+
153
+ it "still returns variant expected" do
154
+ expect(shipment.manifest.first.variant).to eq variant
155
+ end
156
+ end
157
+ end
158
+
159
+ context 'shipping_rates' do
160
+ let(:shipment) { create(:shipment) }
161
+ let(:shipping_method1) { create(:shipping_method) }
162
+ let(:shipping_method2) { create(:shipping_method) }
163
+ let(:shipping_rates) { [
164
+ Spree::ShippingRate.new(shipping_method: shipping_method1, cost: 10.00, selected: true),
165
+ Spree::ShippingRate.new(shipping_method: shipping_method2, cost: 20.00)
166
+ ] }
167
+
168
+ it 'returns shipping_method from selected shipping_rate' do
169
+ shipment.shipping_rates.delete_all
170
+ shipment.shipping_rates.create shipping_method: shipping_method1, cost: 10.00, selected: true
171
+ expect(shipment.shipping_method).to eq shipping_method1
172
+ end
173
+
174
+ context 'refresh_rates' do
175
+ let(:mock_estimator) { double('estimator', shipping_rates: shipping_rates) }
176
+ before { allow(shipment).to receive(:can_get_rates?){ true } }
177
+
178
+ it 'should request new rates, and maintain shipping_method selection' do
179
+ expect(Spree::Stock::Estimator).to receive(:new).with(shipment.order).and_return(mock_estimator)
180
+ allow(shipment).to receive_messages(shipping_method: shipping_method2)
181
+
182
+ expect(shipment.refresh_rates).to eq(shipping_rates)
183
+ expect(shipment.reload.selected_shipping_rate.shipping_method_id).to eq(shipping_method2.id)
184
+ end
185
+
186
+ it 'should handle no shipping_method selection' do
187
+ expect(Spree::Stock::Estimator).to receive(:new).with(shipment.order).and_return(mock_estimator)
188
+ allow(shipment).to receive_messages(shipping_method: nil)
189
+ expect(shipment.refresh_rates).to eq(shipping_rates)
190
+ expect(shipment.reload.selected_shipping_rate).not_to be_nil
191
+ end
192
+
193
+ it 'should not refresh if shipment is shipped' do
194
+ expect(Spree::Stock::Estimator).not_to receive(:new)
195
+ shipment.shipping_rates.delete_all
196
+ allow(shipment).to receive_messages(shipped?: true)
197
+ expect(shipment.refresh_rates).to eq([])
198
+ end
199
+
200
+ it "can't get rates without a shipping address" do
201
+ shipment.order(ship_address: nil)
202
+ expect(shipment.refresh_rates).to eq([])
203
+ end
204
+
205
+ context 'to_package' do
206
+ let(:inventory_units) do
207
+ [build(:inventory_unit, line_item: line_item, variant: variant, state: 'on_hand'),
208
+ build(:inventory_unit, line_item: line_item, variant: variant, state: 'backordered')]
209
+ end
210
+
211
+ before do
212
+ allow(shipment).to receive(:inventory_units) { inventory_units }
213
+ allow(inventory_units).to receive_message_chain(:includes, :joins).and_return inventory_units
214
+ end
215
+
216
+ it 'should use symbols for states when adding contents to package' do
217
+ package = shipment.to_package
218
+ expect(package.on_hand.count).to eq 1
219
+ expect(package.backordered.count).to eq 1
220
+ end
221
+ end
222
+ end
223
+ end
224
+
225
+ context "#update!" do
226
+ shared_examples_for "immutable once shipped" do
227
+ it "should remain in shipped state once shipped" do
228
+ shipment.state = 'shipped'
229
+ expect(shipment).to receive(:update_columns).with(state: 'shipped', updated_at: kind_of(Time))
230
+ shipment.update!(order)
231
+ end
232
+ end
233
+
234
+ shared_examples_for "pending if backordered" do
235
+ it "should have a state of pending if backordered" do
236
+ allow(shipment).to receive_messages(inventory_units: [mock_model(Spree::InventoryUnit, backordered?: true)])
237
+ expect(shipment).to receive(:update_columns).with(state: 'pending', updated_at: kind_of(Time))
238
+ shipment.update!(order)
239
+ end
240
+ end
241
+
242
+ context "when order cannot ship" do
243
+ before { allow(order).to receive_messages can_ship?: false }
244
+ it "should result in a 'pending' state" do
245
+ expect(shipment).to receive(:update_columns).with(state: 'pending', updated_at: kind_of(Time))
246
+ shipment.update!(order)
247
+ end
248
+ end
249
+
250
+ context "when order is paid" do
251
+ before { allow(order).to receive_messages paid?: true }
252
+ it "should result in a 'ready' state" do
253
+ expect(shipment).to receive(:update_columns).with(state: 'ready', updated_at: kind_of(Time))
254
+ shipment.update!(order)
255
+ end
256
+ it_should_behave_like 'immutable once shipped'
257
+ it_should_behave_like 'pending if backordered'
258
+ end
259
+
260
+ context "when payment is not required" do
261
+ before do
262
+ @original_require_payment = Spree::Config[:require_payment_to_ship]
263
+ Spree::Config[:require_payment_to_ship] = false
264
+ end
265
+
266
+ after do
267
+ Spree::Config[:require_payment_to_ship] = @original_require_payment
268
+ end
269
+
270
+ it "should result in a 'ready' state" do
271
+ expect(shipment).to receive(:update_columns).with(state: 'ready', updated_at: kind_of(Time))
272
+ shipment.update!(order)
273
+ end
274
+ it_should_behave_like 'immutable once shipped'
275
+ it_should_behave_like 'pending if backordered'
276
+ end
277
+
278
+ context "when order has balance due" do
279
+ before { allow(order).to receive_messages paid?: false }
280
+ it "should result in a 'pending' state" do
281
+ shipment.state = 'ready'
282
+ expect(shipment).to receive(:update_columns).with(state: 'pending', updated_at: kind_of(Time))
283
+ shipment.update!(order)
284
+ end
285
+ it_should_behave_like 'immutable once shipped'
286
+ it_should_behave_like 'pending if backordered'
287
+ end
288
+
289
+ context "when order has a credit owed" do
290
+ before { allow(order).to receive_messages payment_state: 'credit_owed', paid?: true }
291
+ it "should result in a 'ready' state" do
292
+ shipment.state = 'pending'
293
+ expect(shipment).to receive(:update_columns).with(state: 'ready', updated_at: kind_of(Time))
294
+ shipment.update!(order)
295
+ end
296
+ it_should_behave_like 'immutable once shipped'
297
+ it_should_behave_like 'pending if backordered'
298
+ end
299
+
300
+ context "when shipment state changes to shipped" do
301
+ it "should call after_ship" do
302
+ shipment.state = 'pending'
303
+ expect(shipment).to receive :after_ship
304
+ allow(shipment).to receive_messages determine_state: 'shipped'
305
+ expect(shipment).to receive(:update_columns).with(state: 'shipped', updated_at: kind_of(Time))
306
+ shipment.update!(order)
307
+ end
308
+
309
+ # Regression test for #4347
310
+ context "with adjustments" do
311
+ before do
312
+ shipment.adjustments << Spree::Adjustment.create(order: order, label: "Label", amount: 5)
313
+ end
314
+
315
+ it "transitions to shipped" do
316
+ shipment.update_column(:state, "ready")
317
+ expect { shipment.ship! }.not_to raise_error
318
+ end
319
+ end
320
+ end
321
+ end
322
+
323
+ context "when order is completed" do
324
+ after { Spree::Config.set track_inventory_levels: true }
325
+
326
+ before do
327
+ allow(order).to receive_messages completed?: true
328
+ allow(order).to receive_messages canceled?: false
329
+ end
330
+
331
+ context "with inventory tracking" do
332
+ before { Spree::Config.set track_inventory_levels: true }
333
+
334
+ it "should validate with inventory" do
335
+ shipment.inventory_units = [create(:inventory_unit)]
336
+ expect(shipment.valid?).to be true
337
+ end
338
+ end
339
+
340
+ context "without inventory tracking" do
341
+ before { Spree::Config.set track_inventory_levels: false }
342
+
343
+ it "should validate with no inventory" do
344
+ expect(shipment.valid?).to be true
345
+ end
346
+ end
347
+ end
348
+
349
+ context "#cancel" do
350
+ it 'cancels the shipment' do
351
+ allow(shipment.order).to receive(:update!)
352
+
353
+ shipment.state = 'pending'
354
+ expect(shipment).to receive(:after_cancel)
355
+ shipment.cancel!
356
+ expect(shipment.state).to eq 'canceled'
357
+ end
358
+
359
+ it 'restocks the items' do
360
+ variant = shipment.inventory_units.first.variant
361
+ shipment.stock_location = mock_model(Spree::StockLocation)
362
+ expect(shipment.stock_location).to receive(:restock).with(variant, 1, shipment)
363
+ shipment.after_cancel
364
+ end
365
+
366
+ context "with backordered inventory units" do
367
+ let(:order) { create(:order) }
368
+ let(:variant) { create(:variant) }
369
+ let(:other_order) { create(:order) }
370
+
371
+ before do
372
+ order.contents.add variant
373
+ order.create_proposed_shipments
374
+
375
+ other_order.contents.add variant
376
+ other_order.create_proposed_shipments
377
+ end
378
+
379
+ it "doesn't fill backorders when restocking inventory units" do
380
+ shipment = order.shipments.first
381
+ expect(shipment.inventory_units.count).to eq 1
382
+ expect(shipment.inventory_units.first).to be_backordered
383
+
384
+ other_shipment = other_order.shipments.first
385
+ expect(other_shipment.inventory_units.count).to eq 1
386
+ expect(other_shipment.inventory_units.first).to be_backordered
387
+
388
+ expect {
389
+ shipment.cancel!
390
+ }.not_to change { other_shipment.inventory_units.first.state }
391
+ end
392
+ end
393
+ end
394
+
395
+ context "#resume" do
396
+ let(:inventory_unit) { create(:inventory_unit) }
397
+
398
+ before { shipment.state = 'canceled' }
399
+
400
+ context "when order cannot ship" do
401
+ before { allow(order).to receive_messages(can_ship?: false) }
402
+ it "should result in a 'pending' state" do
403
+ shipment.resume!
404
+ expect(shipment.state).to eq 'pending'
405
+ end
406
+ end
407
+
408
+ context "when order is not paid" do
409
+ before { allow(order).to receive_messages(paid?: false) }
410
+ it "should result in a 'ready' state" do
411
+ shipment.resume!
412
+ expect(shipment.state).to eq 'pending'
413
+ end
414
+ end
415
+
416
+ context "when any inventory is backordered" do
417
+ before { allow_any_instance_of(Spree::InventoryUnit).to receive(:backordered?).and_return(true) }
418
+ it "should result in a 'ready' state" do
419
+ shipment.resume!
420
+ expect(shipment.state).to eq 'pending'
421
+ end
422
+ end
423
+
424
+ context "when the order is paid, shippable, and not backordered" do
425
+ before do
426
+ allow(order).to receive_messages(can_ship?: true)
427
+ allow(order).to receive_messages(paid?: true)
428
+ allow_any_instance_of(Spree::InventoryUnit).to receive(:backordered?).and_return(false)
429
+ end
430
+
431
+ it "should result in a 'ready' state" do
432
+ shipment.resume!
433
+ expect(shipment.state).to eq 'ready'
434
+ end
435
+ end
436
+
437
+ it 'unstocks them items' do
438
+ variant = shipment.inventory_units.first.variant
439
+ shipment.stock_location = mock_model(Spree::StockLocation)
440
+ expect(shipment.stock_location).to receive(:unstock).with(variant, 1, shipment)
441
+ shipment.after_resume
442
+ end
443
+ end
444
+
445
+ context "#ship" do
446
+ context "when the shipment is canceled" do
447
+ let(:address){ create(:address) }
448
+ let(:order){ create(:order_with_line_items, ship_address: address) }
449
+ let(:shipment_with_inventory_units) { create(:shipment, order: order, address: address, state: 'canceled') }
450
+ let(:subject) { shipment_with_inventory_units.ship! }
451
+ before do
452
+ allow(order).to receive(:update!)
453
+ allow(shipment_with_inventory_units).to receive_messages(require_inventory: false, update_order: true)
454
+ end
455
+
456
+ it 'unstocks them items' do
457
+ expect(shipment_with_inventory_units.stock_location).to receive(:unstock).with(an_instance_of(Spree::Variant), 1, shipment_with_inventory_units)
458
+ subject
459
+ end
460
+ end
461
+
462
+ ['ready', 'canceled'].each do |state|
463
+ context "from #{state}" do
464
+ before do
465
+ allow(order).to receive(:update!)
466
+ allow(shipment).to receive_messages(require_inventory: false, update_order: true, state: state)
467
+ end
468
+
469
+ it "should call fulfill_order_with_stock_location" do
470
+ expect(Spree::OrderStockLocation).to(
471
+ receive(:fulfill_for_order_with_stock_location).
472
+ with(order, stock_location)
473
+ )
474
+ shipment.ship!
475
+ end
476
+
477
+ it "finalizes adjustments" do
478
+ shipment.adjustments.each do |adjustment|
479
+ expect(adjustment).to receive(:finalize!)
480
+ end
481
+ shipment.ship!
482
+ end
483
+ end
484
+ end
485
+ end
486
+
487
+ context "#ready" do
488
+ # Regression test for #2040
489
+ it "cannot ready a shipment for an order if the order is unpaid" do
490
+ expect(order).to receive_messages(paid?: false)
491
+ expect(shipment).not_to be_can_ready
492
+ end
493
+ end
494
+
495
+ context "updates cost when selected shipping rate is present" do
496
+ let(:shipment) { create(:shipment) }
497
+
498
+ before { allow(shipment).to receive_message_chain :selected_shipping_rate, cost: 5 }
499
+
500
+ it "updates shipment totals" do
501
+ shipment.update_amounts
502
+ expect(shipment.reload.cost).to eq(5)
503
+ end
504
+
505
+ it "factors in additional adjustments to adjustment total" do
506
+ shipment.adjustments.create!(
507
+ order: order,
508
+ label: "Additional",
509
+ amount: 5,
510
+ included: false,
511
+ state: "closed"
512
+ )
513
+ shipment.update_amounts
514
+ expect(shipment.reload.adjustment_total).to eq(5)
515
+ end
516
+
517
+ it "does not factor in included adjustments to adjustment total" do
518
+ shipment.adjustments.create!(
519
+ order: order,
520
+ label: "Included",
521
+ amount: 5,
522
+ included: true,
523
+ state: "closed"
524
+ )
525
+ shipment.update_amounts
526
+ expect(shipment.reload.adjustment_total).to eq(0)
527
+ end
528
+ end
529
+
530
+ context "changes shipping rate via general update" do
531
+ let(:order) do
532
+ Spree::Order.create(
533
+ payment_total: 100, payment_state: 'paid', total: 100, item_total: 100
534
+ )
535
+ end
536
+
537
+ let(:shipment) { Spree::Shipment.create order_id: order.id }
538
+
539
+ let(:shipping_rate) do
540
+ Spree::ShippingRate.create shipment_id: shipment.id, cost: 10
541
+ end
542
+
543
+ before do
544
+ shipment.update_attributes_and_order selected_shipping_rate_id: shipping_rate.id
545
+ end
546
+
547
+ it "updates everything around order shipment total and state" do
548
+ expect(shipment.cost.to_f).to eq 10
549
+ expect(shipment.state).to eq 'pending'
550
+ expect(shipment.order.total.to_f).to eq 110
551
+ expect(shipment.order.payment_state).to eq 'balance_due'
552
+ end
553
+ end
554
+
555
+ context "after_save" do
556
+ context "line item changes" do
557
+ before do
558
+ shipment.cost = shipment.cost + 10
559
+ end
560
+
561
+ it "triggers adjustment total recalculation" do
562
+ expect(shipment).to receive(:recalculate_adjustments)
563
+ shipment.save
564
+ end
565
+
566
+ it "does not trigger adjustment recalculation if shipment has shipped" do
567
+ shipment.state = 'shipped'
568
+ expect(shipment).not_to receive(:recalculate_adjustments)
569
+ shipment.save
570
+ end
571
+ end
572
+
573
+ context "line item does not change" do
574
+ it "does not trigger adjustment total recalculation" do
575
+ expect(shipment).not_to receive(:recalculate_adjustments)
576
+ shipment.save
577
+ end
578
+ end
579
+ end
580
+
581
+ context "currency" do
582
+ it "returns the order currency" do
583
+ expect(shipment.currency).to eq(order.currency)
584
+ end
585
+ end
586
+
587
+ context "nil costs" do
588
+ it "sets cost to 0" do
589
+ shipment = Spree::Shipment.new
590
+ shipment.valid?
591
+ expect(shipment.cost).to eq 0
592
+ end
593
+ end
594
+
595
+ context "#tracking_url" do
596
+ subject do
597
+ shipment.tracking_url
598
+ end
599
+
600
+ before do
601
+ shipping_method.update!(tracking_url: "https://example.com/:tracking")
602
+ shipment.tracking = '1Z12345'
603
+ end
604
+
605
+ it "uses shipping method to determine url" do
606
+ is_expected.to eq("https://example.com/1Z12345")
607
+ end
608
+ end
609
+
610
+ context "set up new inventory units" do
611
+ # let(:line_item) { double(
612
+ let(:variant) { double("Variant", id: 9) }
613
+
614
+ let(:inventory_units) { double }
615
+
616
+ let(:params) do
617
+ { variant_id: variant.id, state: 'on_hand', order_id: order.id, line_item_id: line_item.id }
618
+ end
619
+
620
+ before { allow(shipment).to receive_messages inventory_units: inventory_units }
621
+
622
+ it "associates variant and order" do
623
+ expect(inventory_units).to receive(:create).with(params)
624
+ unit = shipment.set_up_inventory('on_hand', variant, order, line_item)
625
+ end
626
+ end
627
+
628
+ # Regression test for #3349
629
+ context "#destroy" do
630
+ it "destroys linked shipping_rates" do
631
+ reflection = Spree::Shipment.reflect_on_association(:shipping_rates)
632
+ expect(reflection.options[:dependent]).to be(:delete_all)
633
+ end
634
+ end
635
+
636
+ # Regression test for #4072 (kinda)
637
+ # The need for this was discovered in the research for #4702
638
+ context "state changes" do
639
+ before do
640
+ # Must be stubbed so transition can succeed
641
+ allow(order).to receive_messages :paid? => true
642
+ end
643
+
644
+ it "are logged to the database" do
645
+ expect(shipment.state_changes).to be_empty
646
+ expect(shipment.ready!).to be true
647
+ expect(shipment.state_changes.count).to eq(1)
648
+ state_change = shipment.state_changes.first
649
+ expect(state_change.previous_state).to eq('pending')
650
+ expect(state_change.next_state).to eq('ready')
651
+ end
652
+ end
653
+
654
+ context "don't require shipment" do
655
+ let(:stock_location) { create(:stock_location, fulfillable: false)}
656
+ let(:unshippable_shipment) do
657
+ create(
658
+ :shipment,
659
+ address: create(:address),
660
+ stock_location: stock_location,
661
+ inventory_units: [build(:inventory_unit)],
662
+ )
663
+ end
664
+
665
+ before { allow(order).to receive_messages paid?: true }
666
+
667
+ it 'proceeds automatically to shipped state' do
668
+ unshippable_shipment.ready!
669
+ expect(unshippable_shipment.state).to eq('shipped')
670
+ end
671
+
672
+ it 'does not send a confirmation email' do
673
+ expect(unshippable_shipment).to_not receive(:send_shipment_email)
674
+ unshippable_shipment.ready!
675
+ unshippable_shipment.inventory_units(true).each do |unit|
676
+ expect(unit.state).to eq('shipped')
677
+ end
678
+ end
679
+ end
680
+
681
+ context "destroy prevention" do
682
+ it "can be destroyed when pending" do
683
+ shipment = create(:shipment, state: "pending")
684
+ expect(shipment.destroy).to be_truthy
685
+ expect { shipment.reload }.to raise_error(ActiveRecord::RecordNotFound)
686
+ end
687
+
688
+ it "cannot be destroyed when ready" do
689
+ shipment = create(:shipment, state: "ready")
690
+ expect(shipment.destroy).to eq false
691
+ expect(shipment.errors.full_messages.join).to match /Cannot destroy/
692
+ expect { shipment.reload }.not_to raise_error
693
+ end
694
+
695
+ it "cannot be destroyed when shipped" do
696
+ shipment = create(:shipment, state: "shipped")
697
+ expect(shipment.destroy).to eq false
698
+ expect(shipment.errors.full_messages.join).to match /Cannot destroy/
699
+ expect { shipment.reload }.not_to raise_error
700
+ end
701
+
702
+ it "cannot be destroyed when canceled" do
703
+ shipment = create(:shipment, state: "canceled")
704
+ expect(shipment.destroy).to eq false
705
+ expect(shipment.errors.full_messages.join).to match /Cannot destroy/
706
+ expect { shipment.reload }.not_to raise_error
707
+ end
708
+ end
709
+ end