spree_core 3.0.5 → 3.0.6

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