solidus_core 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of solidus_core might be problematic. Click here for more details.

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