spree_core 3.0.5 → 3.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/Gemfile +3 -0
  4. data/Rakefile +30 -0
  5. data/app/assets/javascripts/spree.js.coffee.erb +1 -1
  6. data/app/models/spree/ability.rb +1 -1
  7. data/app/models/spree/base.rb +3 -1
  8. data/app/models/spree/order_updater.rb +2 -1
  9. data/app/models/spree/price.rb +7 -12
  10. data/app/models/spree/product.rb +3 -2
  11. data/app/models/spree/reimbursement.rb +1 -1
  12. data/app/models/spree/state.rb +2 -0
  13. data/app/models/spree/zone.rb +1 -1
  14. data/lib/spree/core/version.rb +1 -1
  15. data/lib/spree/testing_support/shoulda_matcher_configuration.rb +6 -0
  16. data/script/rails +9 -0
  17. data/spec/fixtures/thinking-cat.jpg +0 -0
  18. data/spec/helpers/base_helper_spec.rb +137 -0
  19. data/spec/helpers/products_helper_spec.rb +224 -0
  20. data/spec/lib/calculated_adjustments_spec.rb +7 -0
  21. data/spec/lib/i18n_spec.rb +123 -0
  22. data/spec/lib/search/base_spec.rb +86 -0
  23. data/spec/lib/spree/core/controller_helpers/auth_spec.rb +101 -0
  24. data/spec/lib/spree/core/controller_helpers/order_spec.rb +95 -0
  25. data/spec/lib/spree/core/controller_helpers/search_spec.rb +17 -0
  26. data/spec/lib/spree/core/controller_helpers/store_spec.rb +16 -0
  27. data/spec/lib/spree/core/controller_helpers/strong_parameters_spec.rb +39 -0
  28. data/spec/lib/spree/core/delegate_belongs_to_spec.rb +22 -0
  29. data/spec/lib/spree/core/importer/order_spec.rb +502 -0
  30. data/spec/lib/spree/core/validators/email_spec.rb +53 -0
  31. data/spec/lib/spree/localized_number_spec.rb +38 -0
  32. data/spec/lib/spree/migrations_spec.rb +34 -0
  33. data/spec/lib/spree/money_spec.rb +122 -0
  34. data/spec/lib/tasks/exchanges_spec.rb +136 -0
  35. data/spec/mailers/order_mailer_spec.rb +124 -0
  36. data/spec/mailers/reimbursement_mailer_spec.rb +47 -0
  37. data/spec/mailers/shipment_mailer_spec.rb +63 -0
  38. data/spec/mailers/test_mailer_spec.rb +24 -0
  39. data/spec/models/spree/ability_spec.rb +246 -0
  40. data/spec/models/spree/address_spec.rb +291 -0
  41. data/spec/models/spree/adjustable/adjustments_updater_spec.rb +286 -0
  42. data/spec/models/spree/adjustment_spec.rb +163 -0
  43. data/spec/models/spree/app_configuration_spec.rb +23 -0
  44. data/spec/models/spree/asset_spec.rb +25 -0
  45. data/spec/models/spree/calculator/default_tax_spec.rb +127 -0
  46. data/spec/models/spree/calculator/flat_percent_item_total_spec.rb +25 -0
  47. data/spec/models/spree/calculator/flat_rate_spec.rb +47 -0
  48. data/spec/models/spree/calculator/flexi_rate_spec.rb +41 -0
  49. data/spec/models/spree/calculator/percent_on_line_item_spec.rb +15 -0
  50. data/spec/models/spree/calculator/price_sack_spec.rb +30 -0
  51. data/spec/models/spree/calculator/refunds/default_refund_amount_spec.rb +51 -0
  52. data/spec/models/spree/calculator/shipping.rb +8 -0
  53. data/spec/models/spree/calculator/shipping/flat_percent_item_total_spec.rb +23 -0
  54. data/spec/models/spree/calculator/shipping/flat_rate_spec.rb +13 -0
  55. data/spec/models/spree/calculator/shipping/flexi_rate_spec.rb +52 -0
  56. data/spec/models/spree/calculator/shipping/per_item_spec.rb +20 -0
  57. data/spec/models/spree/calculator/shipping/price_sack_spec.rb +29 -0
  58. data/spec/models/spree/calculator/tiered_flat_rate_spec.rb +40 -0
  59. data/spec/models/spree/calculator/tiered_percent_spec.rb +51 -0
  60. data/spec/models/spree/calculator_spec.rb +69 -0
  61. data/spec/models/spree/classification_spec.rb +93 -0
  62. data/spec/models/spree/concerns/display_money_spec.rb +43 -0
  63. data/spec/models/spree/country_spec.rb +18 -0
  64. data/spec/models/spree/credit_card_spec.rb +324 -0
  65. data/spec/models/spree/customer_return_spec.rb +262 -0
  66. data/spec/models/spree/exchange_spec.rb +75 -0
  67. data/spec/models/spree/gateway/bogus_simple.rb +20 -0
  68. data/spec/models/spree/gateway/bogus_spec.rb +13 -0
  69. data/spec/models/spree/gateway_spec.rb +54 -0
  70. data/spec/models/spree/image_spec.rb +5 -0
  71. data/spec/models/spree/inventory_unit_spec.rb +242 -0
  72. data/spec/models/spree/line_item_spec.rb +267 -0
  73. data/spec/models/spree/option_type_spec.rb +14 -0
  74. data/spec/models/spree/option_value_spec.rb +13 -0
  75. data/spec/models/spree/order/address_spec.rb +50 -0
  76. data/spec/models/spree/order/adjustments_spec.rb +29 -0
  77. data/spec/models/spree/order/callbacks_spec.rb +42 -0
  78. data/spec/models/spree/order/checkout_spec.rb +764 -0
  79. data/spec/models/spree/order/currency_updater_spec.rb +32 -0
  80. data/spec/models/spree/order/finalizing_spec.rb +117 -0
  81. data/spec/models/spree/order/helpers_spec.rb +5 -0
  82. data/spec/models/spree/order/payment_spec.rb +214 -0
  83. data/spec/models/spree/order/risk_assessment_spec.rb +84 -0
  84. data/spec/models/spree/order/shipments_spec.rb +43 -0
  85. data/spec/models/spree/order/state_machine_spec.rb +216 -0
  86. data/spec/models/spree/order/tax_spec.rb +84 -0
  87. data/spec/models/spree/order/totals_spec.rb +24 -0
  88. data/spec/models/spree/order/updating_spec.rb +18 -0
  89. data/spec/models/spree/order/validations_spec.rb +15 -0
  90. data/spec/models/spree/order_contents_spec.rb +256 -0
  91. data/spec/models/spree/order_inventory_spec.rb +228 -0
  92. data/spec/models/spree/order_merger_spec.rb +133 -0
  93. data/spec/models/spree/order_spec.rb +954 -0
  94. data/spec/models/spree/order_updater_spec.rb +283 -0
  95. data/spec/models/spree/payment/gateway_options_spec.rb +119 -0
  96. data/spec/models/spree/payment_method_spec.rb +95 -0
  97. data/spec/models/spree/payment_spec.rb +926 -0
  98. data/spec/models/spree/preference_spec.rb +80 -0
  99. data/spec/models/spree/preferences/configuration_spec.rb +30 -0
  100. data/spec/models/spree/preferences/preferable_spec.rb +348 -0
  101. data/spec/models/spree/preferences/scoped_store_spec.rb +58 -0
  102. data/spec/models/spree/preferences/store_spec.rb +46 -0
  103. data/spec/models/spree/price_spec.rb +42 -0
  104. data/spec/models/spree/product/scopes_spec.rb +148 -0
  105. data/spec/models/spree/product_duplicator_spec.rb +103 -0
  106. data/spec/models/spree/product_filter_spec.rb +26 -0
  107. data/spec/models/spree/product_option_type_spec.rb +5 -0
  108. data/spec/models/spree/product_property_spec.rb +11 -0
  109. data/spec/models/spree/product_spec.rb +474 -0
  110. data/spec/models/spree/promotion/actions/create_adjustment_spec.rb +50 -0
  111. data/spec/models/spree/promotion/actions/create_item_adjustments_spec.rb +148 -0
  112. data/spec/models/spree/promotion/actions/create_line_items_spec.rb +86 -0
  113. data/spec/models/spree/promotion/actions/free_shipping_spec.rb +36 -0
  114. data/spec/models/spree/promotion/rules/first_order_spec.rb +75 -0
  115. data/spec/models/spree/promotion/rules/item_total_spec.rb +282 -0
  116. data/spec/models/spree/promotion/rules/one_use_per_user_spec.rb +42 -0
  117. data/spec/models/spree/promotion/rules/option_value_spec.rb +90 -0
  118. data/spec/models/spree/promotion/rules/product_spec.rb +143 -0
  119. data/spec/models/spree/promotion/rules/taxon_spec.rb +102 -0
  120. data/spec/models/spree/promotion/rules/user_logged_in_spec.rb +27 -0
  121. data/spec/models/spree/promotion/rules/user_spec.rb +37 -0
  122. data/spec/models/spree/promotion_action_spec.rb +10 -0
  123. data/spec/models/spree/promotion_category_spec.rb +17 -0
  124. data/spec/models/spree/promotion_handler/cart_spec.rb +102 -0
  125. data/spec/models/spree/promotion_handler/coupon_spec.rb +323 -0
  126. data/spec/models/spree/promotion_handler/free_shipping_spec.rb +48 -0
  127. data/spec/models/spree/promotion_handler/page_spec.rb +44 -0
  128. data/spec/models/spree/promotion_rule_spec.rb +29 -0
  129. data/spec/models/spree/promotion_spec.rb +603 -0
  130. data/spec/models/spree/property_spec.rb +5 -0
  131. data/spec/models/spree/prototype_spec.rb +5 -0
  132. data/spec/models/spree/refund_spec.rb +195 -0
  133. data/spec/models/spree/reimbursement/credit_spec.rb +36 -0
  134. data/spec/models/spree/reimbursement/reimbursement_type_engine_spec.rb +140 -0
  135. data/spec/models/spree/reimbursement/reimbursement_type_validator_spec.rb +83 -0
  136. data/spec/models/spree/reimbursement_performer_spec.rb +30 -0
  137. data/spec/models/spree/reimbursement_spec.rb +215 -0
  138. data/spec/models/spree/reimbursement_tax_calculator_spec.rb +51 -0
  139. data/spec/models/spree/reimbursement_type/credit_spec.rb +53 -0
  140. data/spec/models/spree/reimbursement_type/exchange_spec.rb +46 -0
  141. data/spec/models/spree/reimbursement_type/original_payment_spec.rb +55 -0
  142. data/spec/models/spree/return_authorization_spec.rb +250 -0
  143. data/spec/models/spree/return_item/eligibility_validator/default_spec.rb +77 -0
  144. data/spec/models/spree/return_item/eligibility_validator/inventory_shipped_spec.rb +58 -0
  145. data/spec/models/spree/return_item/eligibility_validator/no_reimbursements_spec.rb +61 -0
  146. data/spec/models/spree/return_item/eligibility_validator/order_completed_spec.rb +32 -0
  147. data/spec/models/spree/return_item/eligibility_validator/rma_required_spec.rb +29 -0
  148. data/spec/models/spree/return_item/eligibility_validator/time_since_purchase_spec.rb +35 -0
  149. data/spec/models/spree/return_item/exchange_variant_eligibility/same_option_value_spec.rb +65 -0
  150. data/spec/models/spree/return_item/exchange_variant_eligibility/same_product_spec.rb +43 -0
  151. data/spec/models/spree/return_item_spec.rb +682 -0
  152. data/spec/models/spree/returns_calculator_spec.rb +14 -0
  153. data/spec/models/spree/shipment_spec.rb +740 -0
  154. data/spec/models/spree/shipping_calculator_spec.rb +45 -0
  155. data/spec/models/spree/shipping_category_spec.rb +5 -0
  156. data/spec/models/spree/shipping_method_spec.rb +88 -0
  157. data/spec/models/spree/shipping_rate_spec.rb +141 -0
  158. data/spec/models/spree/state_spec.rb +18 -0
  159. data/spec/models/spree/stock/availability_validator_spec.rb +36 -0
  160. data/spec/models/spree/stock/content_item_spec.rb +22 -0
  161. data/spec/models/spree/stock/coordinator_spec.rb +51 -0
  162. data/spec/models/spree/stock/differentiator_spec.rb +39 -0
  163. data/spec/models/spree/stock/estimator_spec.rb +154 -0
  164. data/spec/models/spree/stock/inventory_unit_builder_spec.rb +38 -0
  165. data/spec/models/spree/stock/package_spec.rb +194 -0
  166. data/spec/models/spree/stock/packer_spec.rb +70 -0
  167. data/spec/models/spree/stock/prioritizer_spec.rb +125 -0
  168. data/spec/models/spree/stock/quantifier_spec.rb +97 -0
  169. data/spec/models/spree/stock/splitter/backordered_spec.rb +29 -0
  170. data/spec/models/spree/stock/splitter/base_spec.rb +21 -0
  171. data/spec/models/spree/stock/splitter/shipping_category_spec.rb +47 -0
  172. data/spec/models/spree/stock/splitter/weight_spec.rb +32 -0
  173. data/spec/models/spree/stock_item_spec.rb +410 -0
  174. data/spec/models/spree/stock_location_spec.rb +243 -0
  175. data/spec/models/spree/stock_movement_spec.rb +56 -0
  176. data/spec/models/spree/stock_transfer_spec.rb +50 -0
  177. data/spec/models/spree/store_spec.rb +50 -0
  178. data/spec/models/spree/tax_category_spec.rb +27 -0
  179. data/spec/models/spree/tax_rate_spec.rb +382 -0
  180. data/spec/models/spree/taxon_spec.rb +74 -0
  181. data/spec/models/spree/taxonomy_spec.rb +18 -0
  182. data/spec/models/spree/tracker_spec.rb +21 -0
  183. data/spec/models/spree/user_spec.rb +130 -0
  184. data/spec/models/spree/validations/db_maximum_length_validator_spec.rb +24 -0
  185. data/spec/models/spree/variant_spec.rb +523 -0
  186. data/spec/models/spree/zone_spec.rb +444 -0
  187. data/spec/spec_helper.rb +74 -0
  188. data/spec/support/big_decimal.rb +5 -0
  189. data/spec/support/concerns/adjustment_source_spec.rb +23 -0
  190. data/spec/support/concerns/default_price_spec.rb +28 -0
  191. data/spec/support/rake.rb +13 -0
  192. data/spec/support/test_gateway.rb +2 -0
  193. data/spree_core.gemspec +48 -0
  194. metadata +185 -4
@@ -0,0 +1,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