solidus_core 1.1.0 → 1.1.1

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 (228) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -0
  3. data/Rakefile +16 -0
  4. data/script/rails +9 -0
  5. data/solidus_core.gemspec +48 -0
  6. data/spec/fixtures/thinking-cat.jpg +0 -0
  7. data/spec/helpers/base_helper_spec.rb +173 -0
  8. data/spec/helpers/order_helper_spec.rb +12 -0
  9. data/spec/helpers/products_helper_spec.rb +208 -0
  10. data/spec/helpers/taxons_helper_spec.rb +17 -0
  11. data/spec/lib/calculated_adjustments_spec.rb +7 -0
  12. data/spec/lib/i18n_spec.rb +106 -0
  13. data/spec/lib/search/base_spec.rb +86 -0
  14. data/spec/lib/search/variant_spec.rb +112 -0
  15. data/spec/lib/spree/core/controller_helpers/auth_spec.rb +66 -0
  16. data/spec/lib/spree/core/controller_helpers/order_spec.rb +92 -0
  17. data/spec/lib/spree/core/controller_helpers/payment_parameters_spec.rb +80 -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 +24 -0
  23. data/spec/lib/spree/core/importer/order_spec.rb +431 -0
  24. data/spec/lib/spree/core/role_configuration_spec.rb +156 -0
  25. data/spec/lib/spree/core/unreturned_item_charger_spec.rb +130 -0
  26. data/spec/lib/spree/core/validators/email_spec.rb +48 -0
  27. data/spec/lib/spree/localized_number_spec.rb +38 -0
  28. data/spec/lib/spree/migrations_spec.rb +36 -0
  29. data/spec/lib/spree/money_spec.rb +127 -0
  30. data/spec/lib/tasks/exchanges_spec.rb +231 -0
  31. data/spec/lib/tasks/migrations/copy_shipped_shipments_to_cartons_spec.rb +115 -0
  32. data/spec/lib/tasks/order_capturing_spec.rb +56 -0
  33. data/spec/mailers/carton_mailer_spec.rb +55 -0
  34. data/spec/mailers/order_mailer_spec.rb +135 -0
  35. data/spec/mailers/reimbursement_mailer_spec.rb +40 -0
  36. data/spec/mailers/test_mailer_spec.rb +15 -0
  37. data/spec/models/spree/ability_spec.rb +276 -0
  38. data/spec/models/spree/address_spec.rb +376 -0
  39. data/spec/models/spree/adjustment_reason_spec.rb +13 -0
  40. data/spec/models/spree/adjustment_spec.rb +169 -0
  41. data/spec/models/spree/app_configuration_spec.rb +24 -0
  42. data/spec/models/spree/asset_spec.rb +24 -0
  43. data/spec/models/spree/calculator/default_tax_spec.rb +127 -0
  44. data/spec/models/spree/calculator/flat_percent_item_total_spec.rb +25 -0
  45. data/spec/models/spree/calculator/flat_rate_spec.rb +47 -0
  46. data/spec/models/spree/calculator/flexi_rate_spec.rb +41 -0
  47. data/spec/models/spree/calculator/percent_on_line_item_spec.rb +15 -0
  48. data/spec/models/spree/calculator/price_sack_spec.rb +30 -0
  49. data/spec/models/spree/calculator/refunds/default_refund_amount_spec.rb +60 -0
  50. data/spec/models/spree/calculator/shipping/flat_percent_item_total_spec.rb +23 -0
  51. data/spec/models/spree/calculator/shipping/flat_rate_spec.rb +13 -0
  52. data/spec/models/spree/calculator/shipping/flexi_rate_spec.rb +52 -0
  53. data/spec/models/spree/calculator/shipping/per_item_spec.rb +20 -0
  54. data/spec/models/spree/calculator/shipping/price_sack_spec.rb +30 -0
  55. data/spec/models/spree/calculator/tiered_flat_rate_spec.rb +36 -0
  56. data/spec/models/spree/calculator/tiered_percent_spec.rb +47 -0
  57. data/spec/models/spree/calculator_spec.rb +36 -0
  58. data/spec/models/spree/carton_spec.rb +133 -0
  59. data/spec/models/spree/classification_spec.rb +93 -0
  60. data/spec/models/spree/concerns/display_money_spec.rb +43 -0
  61. data/spec/models/spree/concerns/ordered_property_value_list_spec.rb +25 -0
  62. data/spec/models/spree/concerns/user_address_book_spec.rb +332 -0
  63. data/spec/models/spree/concerns/user_methods_spec.rb +41 -0
  64. data/spec/models/spree/credit_card_spec.rb +341 -0
  65. data/spec/models/spree/customer_return_spec.rb +276 -0
  66. data/spec/models/spree/exchange_spec.rb +79 -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 +104 -0
  70. data/spec/models/spree/inventory_unit_spec.rb +307 -0
  71. data/spec/models/spree/item_adjustments_spec.rb +275 -0
  72. data/spec/models/spree/line_item_spec.rb +199 -0
  73. data/spec/models/spree/option_type_spec.rb +14 -0
  74. data/spec/models/spree/option_value_spec.rb +45 -0
  75. data/spec/models/spree/order/address_spec.rb +50 -0
  76. data/spec/models/spree/order/adjustments_spec.rb +27 -0
  77. data/spec/models/spree/order/callbacks_spec.rb +42 -0
  78. data/spec/models/spree/order/checkout_spec.rb +884 -0
  79. data/spec/models/spree/order/currency_updater_spec.rb +32 -0
  80. data/spec/models/spree/order/finalizing_spec.rb +110 -0
  81. data/spec/models/spree/order/payment_spec.rb +243 -0
  82. data/spec/models/spree/order/risk_assessment_spec.rb +68 -0
  83. data/spec/models/spree/order/state_machine_spec.rb +209 -0
  84. data/spec/models/spree/order/tax_spec.rb +84 -0
  85. data/spec/models/spree/order/totals_spec.rb +24 -0
  86. data/spec/models/spree/order/updating_spec.rb +18 -0
  87. data/spec/models/spree/order/validations_spec.rb +15 -0
  88. data/spec/models/spree/order_cancellations_spec.rb +120 -0
  89. data/spec/models/spree/order_capturing_spec.rb +150 -0
  90. data/spec/models/spree/order_contents_spec.rb +307 -0
  91. data/spec/models/spree/order_inventory_spec.rb +228 -0
  92. data/spec/models/spree/order_mutex_spec.rb +85 -0
  93. data/spec/models/spree/order_promotion_spec.rb +31 -0
  94. data/spec/models/spree/order_shipping_spec.rb +241 -0
  95. data/spec/models/spree/order_spec.rb +1482 -0
  96. data/spec/models/spree/order_stock_location_spec.rb +18 -0
  97. data/spec/models/spree/order_updater_spec.rb +283 -0
  98. data/spec/models/spree/payment_method/store_credit_spec.rb +294 -0
  99. data/spec/models/spree/payment_method_spec.rb +147 -0
  100. data/spec/models/spree/payment_spec.rb +1087 -0
  101. data/spec/models/spree/permission_sets/base_spec.rb +12 -0
  102. data/spec/models/spree/permission_sets/configuration_display.rb +82 -0
  103. data/spec/models/spree/permission_sets/configuration_management_spec.rb +50 -0
  104. data/spec/models/spree/permission_sets/dashboard_display_spec.rb +22 -0
  105. data/spec/models/spree/permission_sets/order_display_spec.rb +55 -0
  106. data/spec/models/spree/permission_sets/order_management_spec.rb +42 -0
  107. data/spec/models/spree/permission_sets/product_display_spec.rb +60 -0
  108. data/spec/models/spree/permission_sets/product_management_spec.rb +40 -0
  109. data/spec/models/spree/permission_sets/promotion_display_spec.rb +40 -0
  110. data/spec/models/spree/permission_sets/promotion_management_spec.rb +26 -0
  111. data/spec/models/spree/permission_sets/report_display_spec.rb +24 -0
  112. data/spec/models/spree/permission_sets/restricted_stock_display_spec.rb +41 -0
  113. data/spec/models/spree/permission_sets/restricted_stock_management_spec.rb +41 -0
  114. data/spec/models/spree/permission_sets/restricted_stock_transfer_display_spec.rb +50 -0
  115. data/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb +160 -0
  116. data/spec/models/spree/permission_sets/stock_display_spec.rb +24 -0
  117. data/spec/models/spree/permission_sets/stock_management_spec.rb +22 -0
  118. data/spec/models/spree/permission_sets/stock_transfer_display_spec.rb +24 -0
  119. data/spec/models/spree/permission_sets/stock_transfer_management_spec.rb +25 -0
  120. data/spec/models/spree/permission_sets/user_display_spec.rb +38 -0
  121. data/spec/models/spree/permission_sets/user_management_spec.rb +48 -0
  122. data/spec/models/spree/preference_spec.rb +80 -0
  123. data/spec/models/spree/preferences/configuration_spec.rb +30 -0
  124. data/spec/models/spree/preferences/preferable_spec.rb +294 -0
  125. data/spec/models/spree/preferences/scoped_store_spec.rb +60 -0
  126. data/spec/models/spree/preferences/static_model_preferences_spec.rb +78 -0
  127. data/spec/models/spree/preferences/statically_configurable_spec.rb +60 -0
  128. data/spec/models/spree/preferences/store_spec.rb +39 -0
  129. data/spec/models/spree/price_spec.rb +42 -0
  130. data/spec/models/spree/product/scopes_spec.rb +116 -0
  131. data/spec/models/spree/product_duplicator_spec.rb +103 -0
  132. data/spec/models/spree/product_filter_spec.rb +26 -0
  133. data/spec/models/spree/product_property_spec.rb +18 -0
  134. data/spec/models/spree/product_spec.rb +504 -0
  135. data/spec/models/spree/promotion/actions/create_adjustment_spec.rb +96 -0
  136. data/spec/models/spree/promotion/actions/create_item_adjustments_spec.rb +165 -0
  137. data/spec/models/spree/promotion/actions/create_quantity_adjustments_spec.rb +115 -0
  138. data/spec/models/spree/promotion/actions/free_shipping_spec.rb +40 -0
  139. data/spec/models/spree/promotion/rules/first_order_spec.rb +75 -0
  140. data/spec/models/spree/promotion/rules/first_repeat_purchase_since_spec.rb +69 -0
  141. data/spec/models/spree/promotion/rules/item_total_spec.rb +67 -0
  142. data/spec/models/spree/promotion/rules/nth_order_spec.rb +70 -0
  143. data/spec/models/spree/promotion/rules/one_use_per_user_spec.rb +42 -0
  144. data/spec/models/spree/promotion/rules/option_value_spec.rb +94 -0
  145. data/spec/models/spree/promotion/rules/product_spec.rb +143 -0
  146. data/spec/models/spree/promotion/rules/taxon_spec.rb +102 -0
  147. data/spec/models/spree/promotion/rules/user_logged_in_spec.rb +27 -0
  148. data/spec/models/spree/promotion/rules/user_spec.rb +37 -0
  149. data/spec/models/spree/promotion_builder_spec.rb +118 -0
  150. data/spec/models/spree/promotion_category_spec.rb +17 -0
  151. data/spec/models/spree/promotion_code/code_builder_spec.rb +79 -0
  152. data/spec/models/spree/promotion_code_spec.rb +187 -0
  153. data/spec/models/spree/promotion_handler/cart_spec.rb +130 -0
  154. data/spec/models/spree/promotion_handler/coupon_spec.rb +335 -0
  155. data/spec/models/spree/promotion_handler/free_shipping_spec.rb +47 -0
  156. data/spec/models/spree/promotion_handler/page_spec.rb +44 -0
  157. data/spec/models/spree/promotion_rule_spec.rb +28 -0
  158. data/spec/models/spree/promotion_spec.rb +776 -0
  159. data/spec/models/spree/refund_spec.rb +192 -0
  160. data/spec/models/spree/reimbursement/credit_spec.rb +36 -0
  161. data/spec/models/spree/reimbursement/reimbursement_type_engine_spec.rb +140 -0
  162. data/spec/models/spree/reimbursement/reimbursement_type_validator_spec.rb +83 -0
  163. data/spec/models/spree/reimbursement_performer_spec.rb +30 -0
  164. data/spec/models/spree/reimbursement_spec.rb +231 -0
  165. data/spec/models/spree/reimbursement_tax_calculator_spec.rb +51 -0
  166. data/spec/models/spree/reimbursement_type/credit_spec.rb +53 -0
  167. data/spec/models/spree/reimbursement_type/exchange_spec.rb +46 -0
  168. data/spec/models/spree/reimbursement_type/original_payment_spec.rb +107 -0
  169. data/spec/models/spree/reimbursement_type/store_credit_spec.rb +97 -0
  170. data/spec/models/spree/return_authorization_spec.rb +290 -0
  171. data/spec/models/spree/return_item/eligibility_validator/default_spec.rb +77 -0
  172. data/spec/models/spree/return_item/eligibility_validator/inventory_shipped_spec.rb +58 -0
  173. data/spec/models/spree/return_item/eligibility_validator/no_reimbursements_spec.rb +85 -0
  174. data/spec/models/spree/return_item/eligibility_validator/order_completed_spec.rb +32 -0
  175. data/spec/models/spree/return_item/eligibility_validator/rma_required_spec.rb +29 -0
  176. data/spec/models/spree/return_item/eligibility_validator/time_since_purchase_spec.rb +35 -0
  177. data/spec/models/spree/return_item/exchange_variant_eligibility/same_option_value_spec.rb +65 -0
  178. data/spec/models/spree/return_item/exchange_variant_eligibility/same_product_spec.rb +43 -0
  179. data/spec/models/spree/return_item_spec.rb +776 -0
  180. data/spec/models/spree/returns_calculator_spec.rb +14 -0
  181. data/spec/models/spree/shipment_spec.rb +753 -0
  182. data/spec/models/spree/shipping_calculator_spec.rb +45 -0
  183. data/spec/models/spree/shipping_manifest_spec.rb +94 -0
  184. data/spec/models/spree/shipping_method_spec.rb +88 -0
  185. data/spec/models/spree/shipping_rate_spec.rb +142 -0
  186. data/spec/models/spree/state_spec.rb +14 -0
  187. data/spec/models/spree/stock/availability_validator_spec.rb +83 -0
  188. data/spec/models/spree/stock/coordinator_spec.rb +116 -0
  189. data/spec/models/spree/stock/differentiator_spec.rb +39 -0
  190. data/spec/models/spree/stock/estimator_spec.rb +146 -0
  191. data/spec/models/spree/stock/inventory_unit_builder_spec.rb +38 -0
  192. data/spec/models/spree/stock/package_spec.rb +163 -0
  193. data/spec/models/spree/stock/packer_spec.rb +91 -0
  194. data/spec/models/spree/stock/prioritizer_spec.rb +125 -0
  195. data/spec/models/spree/stock/quantifier_spec.rb +115 -0
  196. data/spec/models/spree/stock/splitter/backordered_spec.rb +29 -0
  197. data/spec/models/spree/stock/splitter/base_spec.rb +21 -0
  198. data/spec/models/spree/stock/splitter/shipping_category_spec.rb +50 -0
  199. data/spec/models/spree/stock/splitter/weight_spec.rb +29 -0
  200. data/spec/models/spree/stock_item_spec.rb +444 -0
  201. data/spec/models/spree/stock_location_spec.rb +279 -0
  202. data/spec/models/spree/stock_movement_spec.rb +56 -0
  203. data/spec/models/spree/stock_transfer_spec.rb +290 -0
  204. data/spec/models/spree/store_credit_category_spec.rb +17 -0
  205. data/spec/models/spree/store_credit_event_spec.rb +314 -0
  206. data/spec/models/spree/store_credit_spec.rb +876 -0
  207. data/spec/models/spree/store_spec.rb +55 -0
  208. data/spec/models/spree/tax_category_spec.rb +27 -0
  209. data/spec/models/spree/tax_rate_spec.rb +378 -0
  210. data/spec/models/spree/taxon_spec.rb +74 -0
  211. data/spec/models/spree/taxonomy_spec.rb +18 -0
  212. data/spec/models/spree/tracker_spec.rb +21 -0
  213. data/spec/models/spree/transfer_item_spec.rb +264 -0
  214. data/spec/models/spree/unit_cancel_spec.rb +149 -0
  215. data/spec/models/spree/user_spec.rb +246 -0
  216. data/spec/models/spree/validations/db_maximum_length_validator_spec.rb +23 -0
  217. data/spec/models/spree/variant/scopes_spec.rb +55 -0
  218. data/spec/models/spree/variant_property_rule_condition_spec.rb +15 -0
  219. data/spec/models/spree/variant_property_rule_spec.rb +83 -0
  220. data/spec/models/spree/variant_property_rule_value_spec.rb +18 -0
  221. data/spec/models/spree/variant_spec.rb +601 -0
  222. data/spec/models/spree/zone_spec.rb +305 -0
  223. data/spec/spec_helper.rb +80 -0
  224. data/spec/support/big_decimal.rb +5 -0
  225. data/spec/support/concerns/default_price.rb +34 -0
  226. data/spec/support/dummy_ability.rb +4 -0
  227. data/spec/support/test_gateway.rb +2 -0
  228. metadata +242 -2
@@ -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,753 @@
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
+ describe "precision of pre_tax_amount" do
29
+ let!(:line_item) { create :line_item, pre_tax_amount: 4.2051 }
30
+
31
+ it "keeps four digits of precision even when reloading" do
32
+ expect(line_item.reload.pre_tax_amount).to eq(4.2051)
33
+ end
34
+ end
35
+
36
+ # Regression test for #4063
37
+ context "number generation" do
38
+ before do
39
+ allow(order).to receive :update!
40
+ end
41
+
42
+ it "generates a number containing a letter + 11 numbers" do
43
+ shipment.save
44
+ expect(shipment.number[0]).to eq("H")
45
+ expect(/\d{11}/.match(shipment.number)).not_to be_nil
46
+ expect(shipment.number.length).to eq(12)
47
+ end
48
+ end
49
+
50
+ it 'is backordered if one if its inventory_units is backordered' do
51
+ shipment.inventory_units = [
52
+ build(:inventory_unit, state: 'backordered', shipment: nil),
53
+ build(:inventory_unit, state: 'shipped', shipment: nil),
54
+ ]
55
+ expect(shipment).to be_backordered
56
+ end
57
+
58
+ context '#determine_state' do
59
+ it 'returns canceled if order is canceled?' do
60
+ allow(order).to receive_messages canceled?: true
61
+ expect(shipment.determine_state(order)).to eq 'canceled'
62
+ end
63
+
64
+ it 'returns pending unless order.can_ship?' do
65
+ allow(order).to receive_messages can_ship?: false
66
+ expect(shipment.determine_state(order)).to eq 'pending'
67
+ end
68
+
69
+ it 'returns pending if backordered' do
70
+ allow(shipment).to receive_messages inventory_units: [mock_model(Spree::InventoryUnit, backordered?: true)]
71
+ expect(shipment.determine_state(order)).to eq 'pending'
72
+ end
73
+
74
+ it 'returns shipped when already shipped' do
75
+ allow(shipment).to receive_messages state: 'shipped'
76
+ expect(shipment.determine_state(order)).to eq 'shipped'
77
+ end
78
+
79
+ it 'returns pending when unpaid' do
80
+ allow(order).to receive_messages paid?: false
81
+ expect(shipment.determine_state(order)).to eq 'pending'
82
+ end
83
+
84
+ it 'returns ready when paid' do
85
+ allow(order).to receive_messages paid?: true
86
+ expect(shipment.determine_state(order)).to eq 'ready'
87
+ end
88
+ end
89
+
90
+ context "display_amount" do
91
+ it "retuns a Spree::Money" do
92
+ shipment.cost = 21.22
93
+ expect(shipment.display_amount).to eq(Spree::Money.new(21.22))
94
+ end
95
+ end
96
+
97
+ context "display_final_price" do
98
+ it "retuns a Spree::Money" do
99
+ allow(shipment).to receive(:final_price) { 21.22 }
100
+ expect(shipment.display_final_price).to eq(Spree::Money.new(21.22))
101
+ end
102
+ end
103
+
104
+ context "display_item_cost" do
105
+ it "retuns a Spree::Money" do
106
+ allow(shipment).to receive(:item_cost) { 21.22 }
107
+ expect(shipment.display_item_cost).to eq(Spree::Money.new(21.22))
108
+ end
109
+ end
110
+
111
+ context "#item_cost" do
112
+ it 'should equal line items final amount with tax' do
113
+ shipment = create(:shipment, order: create(:order_with_totals))
114
+ create :tax_adjustment, adjustable: shipment.order.line_items.first, order: shipment.order
115
+ expect(shipment.item_cost).to eql(11.0)
116
+ end
117
+ end
118
+
119
+ it "#discounted_cost" do
120
+ shipment = create(:shipment)
121
+ shipment.cost = 10
122
+ shipment.promo_total = -1
123
+ expect(shipment.discounted_cost).to eq(9)
124
+ end
125
+
126
+ it "#tax_total with included taxes" do
127
+ shipment = Spree::Shipment.new
128
+ expect(shipment.tax_total).to eq(0)
129
+ shipment.included_tax_total = 10
130
+ expect(shipment.tax_total).to eq(10)
131
+ end
132
+
133
+ it "#tax_total with additional taxes" do
134
+ shipment = Spree::Shipment.new
135
+ expect(shipment.tax_total).to eq(0)
136
+ shipment.additional_tax_total = 10
137
+ expect(shipment.tax_total).to eq(10)
138
+ end
139
+
140
+ it "#final_price" do
141
+ shipment = Spree::Shipment.new
142
+ shipment.cost = 10
143
+ shipment.adjustment_total = -2
144
+ shipment.included_tax_total = 1
145
+ expect(shipment.final_price).to eq(8)
146
+ end
147
+
148
+ context "manifest" do
149
+ let(:order) { Spree::Order.create }
150
+ let(:variant) { create(:variant) }
151
+ let!(:line_item) { order.contents.add variant }
152
+ let!(:shipment) { order.create_proposed_shipments.first }
153
+
154
+ it "returns variant expected" do
155
+ expect(shipment.manifest.first.variant).to eq variant
156
+ end
157
+
158
+ context "variant was removed" do
159
+ before { variant.destroy }
160
+
161
+ it "still returns variant expected" do
162
+ expect(shipment.manifest.first.variant).to eq variant
163
+ end
164
+ end
165
+ end
166
+
167
+ context 'shipping_rates' do
168
+ let(:shipment) { create(:shipment) }
169
+ let(:shipping_method1) { create(:shipping_method) }
170
+ let(:shipping_method2) { create(:shipping_method) }
171
+ let(:shipping_rates) { [
172
+ Spree::ShippingRate.new(shipping_method: shipping_method1, cost: 10.00, selected: true),
173
+ Spree::ShippingRate.new(shipping_method: shipping_method2, cost: 20.00)
174
+ ] }
175
+
176
+ it 'returns shipping_method from selected shipping_rate' do
177
+ shipment.shipping_rates.delete_all
178
+ shipment.shipping_rates.create shipping_method: shipping_method1, cost: 10.00, selected: true
179
+ expect(shipment.shipping_method).to eq shipping_method1
180
+ end
181
+
182
+ context 'refresh_rates' do
183
+ let(:mock_estimator) { double('estimator', shipping_rates: shipping_rates) }
184
+ before { allow(shipment).to receive(:can_get_rates?){ true } }
185
+
186
+ it 'should request new rates, and maintain 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: shipping_method2)
189
+
190
+ expect(shipment.refresh_rates).to eq(shipping_rates)
191
+ expect(shipment.reload.selected_shipping_rate.shipping_method_id).to eq(shipping_method2.id)
192
+ end
193
+
194
+ it 'should handle no shipping_method selection' do
195
+ expect(Spree::Stock::Estimator).to receive(:new).with(shipment.order).and_return(mock_estimator)
196
+ allow(shipment).to receive_messages(shipping_method: nil)
197
+ expect(shipment.refresh_rates).to eq(shipping_rates)
198
+ expect(shipment.reload.selected_shipping_rate).not_to be_nil
199
+ end
200
+
201
+ it 'should not refresh if shipment is shipped' do
202
+ expect(Spree::Stock::Estimator).not_to receive(:new)
203
+ shipment.shipping_rates.delete_all
204
+ allow(shipment).to receive_messages(shipped?: true)
205
+ expect(shipment.refresh_rates).to eq([])
206
+ end
207
+
208
+ it "can't get rates without a shipping address" do
209
+ shipment.order(ship_address: nil)
210
+ expect(shipment.refresh_rates).to eq([])
211
+ end
212
+
213
+ context 'to_package' do
214
+ let(:inventory_units) do
215
+ [build(:inventory_unit, line_item: line_item, variant: variant, state: 'on_hand'),
216
+ build(:inventory_unit, line_item: line_item, variant: variant, state: 'backordered')]
217
+ end
218
+
219
+ before do
220
+ allow(shipment).to receive(:inventory_units) { inventory_units }
221
+ allow(inventory_units).to receive_message_chain(:includes, :joins).and_return inventory_units
222
+ end
223
+
224
+ it 'should use symbols for states when adding contents to package' do
225
+ package = shipment.to_package
226
+ expect(package.on_hand.count).to eq 1
227
+ expect(package.backordered.count).to eq 1
228
+ end
229
+ end
230
+ end
231
+ end
232
+
233
+ context "#update!" do
234
+ shared_examples_for "immutable once shipped" do
235
+ it "should remain in shipped state once shipped" do
236
+ shipment.state = 'shipped'
237
+ expect(shipment).to receive(:update_columns).with(state: 'shipped', updated_at: kind_of(Time))
238
+ shipment.update!(order)
239
+ end
240
+ end
241
+
242
+ shared_examples_for "pending if backordered" do
243
+ it "should have a state of pending if backordered" do
244
+ allow(shipment).to receive_messages(inventory_units: [mock_model(Spree::InventoryUnit, backordered?: true)])
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 cannot ship" do
251
+ before { allow(order).to receive_messages can_ship?: false }
252
+ it "should result in a 'pending' state" do
253
+ expect(shipment).to receive(:update_columns).with(state: 'pending', updated_at: kind_of(Time))
254
+ shipment.update!(order)
255
+ end
256
+ end
257
+
258
+ context "when order is paid" do
259
+ before { allow(order).to receive_messages paid?: true }
260
+ it "should result in a 'ready' state" do
261
+ expect(shipment).to receive(:update_columns).with(state: 'ready', updated_at: kind_of(Time))
262
+ shipment.update!(order)
263
+ end
264
+ it_should_behave_like 'immutable once shipped'
265
+ it_should_behave_like 'pending if backordered'
266
+ end
267
+
268
+ context "when payment is not required" do
269
+ before do
270
+ @original_require_payment = Spree::Config[:require_payment_to_ship]
271
+ Spree::Config[:require_payment_to_ship] = false
272
+ end
273
+
274
+ after do
275
+ Spree::Config[:require_payment_to_ship] = @original_require_payment
276
+ end
277
+
278
+ it "should result in a 'ready' state" do
279
+ expect(shipment).to receive(:update_columns).with(state: 'ready', updated_at: kind_of(Time))
280
+ shipment.update!(order)
281
+ end
282
+ it_should_behave_like 'immutable once shipped'
283
+ it_should_behave_like 'pending if backordered'
284
+ end
285
+
286
+ context "when order has balance due" do
287
+ before { allow(order).to receive_messages paid?: false }
288
+ it "should result in a 'pending' state" do
289
+ shipment.state = 'ready'
290
+ expect(shipment).to receive(:update_columns).with(state: 'pending', updated_at: kind_of(Time))
291
+ shipment.update!(order)
292
+ end
293
+ it_should_behave_like 'immutable once shipped'
294
+ it_should_behave_like 'pending if backordered'
295
+ end
296
+
297
+ context "when order has a credit owed" do
298
+ before { allow(order).to receive_messages payment_state: 'credit_owed', paid?: true }
299
+ it "should result in a 'ready' state" do
300
+ shipment.state = 'pending'
301
+ expect(shipment).to receive(:update_columns).with(state: 'ready', updated_at: kind_of(Time))
302
+ shipment.update!(order)
303
+ end
304
+ it_should_behave_like 'immutable once shipped'
305
+ it_should_behave_like 'pending if backordered'
306
+ end
307
+
308
+ context "when shipment state changes to shipped" do
309
+ it "should call after_ship" do
310
+ shipment.state = 'pending'
311
+ expect(shipment).to receive :after_ship
312
+ allow(shipment).to receive_messages determine_state: 'shipped'
313
+ expect(shipment).to receive(:update_columns).with(state: 'shipped', updated_at: kind_of(Time))
314
+ shipment.update!(order)
315
+ end
316
+
317
+ # Regression test for #4347
318
+ context "with adjustments" do
319
+ before do
320
+ shipment.adjustments << Spree::Adjustment.create(order: order, label: "Label", amount: 5)
321
+ end
322
+
323
+ it "transitions to shipped" do
324
+ shipment.update_column(:state, "ready")
325
+ expect { shipment.ship! }.not_to raise_error
326
+ end
327
+ end
328
+ end
329
+ end
330
+
331
+ context "when order is completed" do
332
+ after { Spree::Config.set track_inventory_levels: true }
333
+
334
+ before do
335
+ allow(order).to receive_messages completed?: true
336
+ allow(order).to receive_messages canceled?: false
337
+ end
338
+
339
+ context "with inventory tracking" do
340
+ before { Spree::Config.set track_inventory_levels: true }
341
+
342
+ it "should validate with inventory" do
343
+ shipment.inventory_units = [create(:inventory_unit)]
344
+ expect(shipment.valid?).to be true
345
+ end
346
+ end
347
+
348
+ context "without inventory tracking" do
349
+ before { Spree::Config.set track_inventory_levels: false }
350
+
351
+ it "should validate with no inventory" do
352
+ expect(shipment.valid?).to be true
353
+ end
354
+ end
355
+ end
356
+
357
+ context "#cancel" do
358
+ it 'cancels the shipment' do
359
+ allow(shipment.order).to receive(:update!)
360
+
361
+ shipment.state = 'pending'
362
+ expect(shipment).to receive(:after_cancel)
363
+ shipment.cancel!
364
+ expect(shipment.state).to eq 'canceled'
365
+ end
366
+
367
+ it 'restocks the items' do
368
+ variant = shipment.inventory_units.first.variant
369
+ shipment.stock_location = mock_model(Spree::StockLocation)
370
+ expect(shipment.stock_location).to receive(:restock).with(variant, 1, shipment)
371
+ shipment.after_cancel
372
+ end
373
+
374
+ context "with backordered inventory units" do
375
+ let(:order) { create(:order) }
376
+ let(:variant) { create(:variant) }
377
+ let(:other_order) { create(:order) }
378
+
379
+ before do
380
+ order.contents.add variant
381
+ order.create_proposed_shipments
382
+
383
+ other_order.contents.add variant
384
+ other_order.create_proposed_shipments
385
+ end
386
+
387
+ it "doesn't fill backorders when restocking inventory units" do
388
+ shipment = order.shipments.first
389
+ expect(shipment.inventory_units.count).to eq 1
390
+ expect(shipment.inventory_units.first).to be_backordered
391
+
392
+ other_shipment = other_order.shipments.first
393
+ expect(other_shipment.inventory_units.count).to eq 1
394
+ expect(other_shipment.inventory_units.first).to be_backordered
395
+
396
+ expect {
397
+ shipment.cancel!
398
+ }.not_to change { other_shipment.inventory_units.first.state }
399
+ end
400
+ end
401
+ end
402
+
403
+ context "#resume" do
404
+ let(:inventory_unit) { create(:inventory_unit) }
405
+
406
+ before { shipment.state = 'canceled' }
407
+
408
+ context "when order cannot ship" do
409
+ before { allow(order).to receive_messages(can_ship?: false) }
410
+ it "should result in a 'pending' state" do
411
+ shipment.resume!
412
+ expect(shipment.state).to eq 'pending'
413
+ end
414
+ end
415
+
416
+ context "when order is not paid" do
417
+ before { allow(order).to receive_messages(paid?: false) }
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 any inventory is backordered" do
425
+ before { allow_any_instance_of(Spree::InventoryUnit).to receive(:backordered?).and_return(true) }
426
+ it "should result in a 'ready' state" do
427
+ shipment.resume!
428
+ expect(shipment.state).to eq 'pending'
429
+ end
430
+ end
431
+
432
+ context "when the order is paid, shippable, and not backordered" do
433
+ before do
434
+ allow(order).to receive_messages(can_ship?: true)
435
+ allow(order).to receive_messages(paid?: true)
436
+ allow_any_instance_of(Spree::InventoryUnit).to receive(:backordered?).and_return(false)
437
+ end
438
+
439
+ it "should result in a 'ready' state" do
440
+ shipment.resume!
441
+ expect(shipment.state).to eq 'ready'
442
+ end
443
+ end
444
+
445
+ it 'unstocks them items' do
446
+ variant = shipment.inventory_units.first.variant
447
+ shipment.stock_location = mock_model(Spree::StockLocation)
448
+ expect(shipment.stock_location).to receive(:unstock).with(variant, 1, shipment)
449
+ shipment.after_resume
450
+ end
451
+ end
452
+
453
+ context "#ship" do
454
+ context "when the shipment is canceled" do
455
+ let(:address){ create(:address) }
456
+ let(:order){ create(:order_with_line_items, ship_address: address) }
457
+ let(:shipment_with_inventory_units) { create(:shipment, order: order, address: address, state: 'canceled') }
458
+ let(:subject) { shipment_with_inventory_units.ship! }
459
+ before do
460
+ allow(order).to receive(:update!)
461
+ allow(shipment_with_inventory_units).to receive_messages(require_inventory: false, update_order: true)
462
+ end
463
+
464
+ it 'unstocks them items' do
465
+ expect(shipment_with_inventory_units.stock_location).to receive(:unstock).with(an_instance_of(Spree::Variant), 1, shipment_with_inventory_units)
466
+ subject
467
+ end
468
+ end
469
+
470
+ ['ready', 'canceled'].each do |state|
471
+ context "from #{state}" do
472
+ before do
473
+ allow(order).to receive(:update!)
474
+ allow(shipment).to receive_messages(require_inventory: false, update_order: true, state: state)
475
+ end
476
+
477
+ it "should call fulfill_order_with_stock_location" do
478
+ expect(Spree::OrderStockLocation).to(
479
+ receive(:fulfill_for_order_with_stock_location).
480
+ with(order, stock_location)
481
+ )
482
+ shipment.ship!
483
+ end
484
+
485
+ it "finalizes adjustments" do
486
+ shipment.adjustments.each do |adjustment|
487
+ expect(adjustment).to receive(:finalize!)
488
+ end
489
+ shipment.ship!
490
+ end
491
+ end
492
+ end
493
+ end
494
+
495
+ context "#ready" do
496
+ # Regression test for #2040
497
+ it "cannot ready a shipment for an order if the order is unpaid" do
498
+ expect(order).to receive_messages(paid?: false)
499
+ expect(shipment).not_to be_can_ready
500
+ end
501
+ end
502
+
503
+ context "updates cost when selected shipping rate is present" do
504
+ let(:shipment) { create(:shipment) }
505
+
506
+ before { allow(shipment).to receive_message_chain :selected_shipping_rate, cost: 5 }
507
+
508
+ it "updates shipment totals" do
509
+ shipment.update_amounts
510
+ expect(shipment.reload.cost).to eq(5)
511
+ end
512
+
513
+ it "factors in additional adjustments to adjustment total" do
514
+ shipment.adjustments.create!(
515
+ order: order,
516
+ label: "Additional",
517
+ amount: 5,
518
+ included: false,
519
+ finalized: true
520
+ )
521
+ shipment.update_amounts
522
+ expect(shipment.reload.adjustment_total).to eq(5)
523
+ end
524
+
525
+ it "does not factor in included adjustments to adjustment total" do
526
+ shipment.adjustments.create!(
527
+ order: order,
528
+ label: "Included",
529
+ amount: 5,
530
+ included: true,
531
+ finalized: true
532
+ )
533
+ shipment.update_amounts
534
+ expect(shipment.reload.adjustment_total).to eq(0)
535
+ end
536
+ end
537
+
538
+ context "changes shipping rate via general update" do
539
+ let(:order) do
540
+ Spree::Order.create(
541
+ payment_total: 100, payment_state: 'paid', total: 100, item_total: 100
542
+ )
543
+ end
544
+
545
+ let(:shipment) { Spree::Shipment.create order_id: order.id }
546
+
547
+ let(:shipping_rate) do
548
+ Spree::ShippingRate.create shipment_id: shipment.id, cost: 10
549
+ end
550
+
551
+ before do
552
+ shipment.update_attributes_and_order selected_shipping_rate_id: shipping_rate.id
553
+ end
554
+
555
+ it "updates everything around order shipment total and state" do
556
+ expect(shipment.cost.to_f).to eq 10
557
+ expect(shipment.state).to eq 'pending'
558
+ expect(shipment.order.total.to_f).to eq 110
559
+ expect(shipment.order.payment_state).to eq 'balance_due'
560
+ end
561
+ end
562
+
563
+ context "after_save" do
564
+ context "line item changes" do
565
+ before do
566
+ shipment.cost = shipment.cost + 10
567
+ end
568
+
569
+ it "triggers adjustment total recalculation" do
570
+ expect(shipment).to receive(:recalculate_adjustments)
571
+ shipment.save
572
+ end
573
+
574
+ it "does not trigger adjustment recalculation if shipment has shipped" do
575
+ shipment.state = 'shipped'
576
+ expect(shipment).not_to receive(:recalculate_adjustments)
577
+ shipment.save
578
+ end
579
+ end
580
+
581
+ context "line item does not change" do
582
+ it "does not trigger adjustment total recalculation" do
583
+ expect(shipment).not_to receive(:recalculate_adjustments)
584
+ shipment.save
585
+ end
586
+ end
587
+ end
588
+
589
+ context "currency" do
590
+ it "returns the order currency" do
591
+ expect(shipment.currency).to eq(order.currency)
592
+ end
593
+ end
594
+
595
+ context "nil costs" do
596
+ it "sets cost to 0" do
597
+ shipment = Spree::Shipment.new
598
+ shipment.valid?
599
+ expect(shipment.cost).to eq 0
600
+ end
601
+ end
602
+
603
+ context "#tracking_url" do
604
+ subject do
605
+ shipment.tracking_url
606
+ end
607
+
608
+ before do
609
+ shipping_method.update!(tracking_url: "https://example.com/:tracking")
610
+ shipment.tracking = '1Z12345'
611
+ end
612
+
613
+ it "uses shipping method to determine url" do
614
+ is_expected.to eq("https://example.com/1Z12345")
615
+ end
616
+ end
617
+
618
+ context "set up new inventory units" do
619
+ # let(:line_item) { double(
620
+ let(:variant) { double("Variant", id: 9) }
621
+
622
+ let(:inventory_units) { double }
623
+
624
+ let(:params) do
625
+ { variant_id: variant.id, state: 'on_hand', order_id: order.id, line_item_id: line_item.id }
626
+ end
627
+
628
+ before { allow(shipment).to receive_messages inventory_units: inventory_units }
629
+
630
+ it "associates variant and order" do
631
+ expect(inventory_units).to receive(:create).with(params)
632
+ unit = shipment.set_up_inventory('on_hand', variant, order, line_item)
633
+ end
634
+ end
635
+
636
+ # Regression test for #3349
637
+ context "#destroy" do
638
+ it "destroys linked shipping_rates" do
639
+ reflection = Spree::Shipment.reflect_on_association(:shipping_rates)
640
+ expect(reflection.options[:dependent]).to be(:delete_all)
641
+ end
642
+ end
643
+
644
+ # Regression test for #4072 (kinda)
645
+ # The need for this was discovered in the research for #4702
646
+ context "state changes" do
647
+ before do
648
+ # Must be stubbed so transition can succeed
649
+ allow(order).to receive_messages :paid? => true
650
+ end
651
+
652
+ it "are logged to the database" do
653
+ expect(shipment.state_changes).to be_empty
654
+ expect(shipment.ready!).to be true
655
+ expect(shipment.state_changes.count).to eq(1)
656
+ state_change = shipment.state_changes.first
657
+ expect(state_change.previous_state).to eq('pending')
658
+ expect(state_change.next_state).to eq('ready')
659
+ end
660
+ end
661
+
662
+ context "don't require shipment" do
663
+ let(:stock_location) { create(:stock_location, fulfillable: false)}
664
+ let(:unshippable_shipment) do
665
+ create(
666
+ :shipment,
667
+ address: create(:address),
668
+ stock_location: stock_location,
669
+ inventory_units: [build(:inventory_unit)],
670
+ )
671
+ end
672
+
673
+ before { allow(order).to receive_messages paid?: true }
674
+
675
+ it 'proceeds automatically to shipped state' do
676
+ unshippable_shipment.ready!
677
+ expect(unshippable_shipment.state).to eq('shipped')
678
+ end
679
+
680
+ it 'does not send a confirmation email' do
681
+ expect {
682
+ unshippable_shipment.ready!
683
+ unshippable_shipment.inventory_units(true).each do |unit|
684
+ expect(unit.state).to eq('shipped')
685
+ end
686
+ }.not_to change{ ActionMailer::Base.deliveries.count }
687
+ end
688
+ end
689
+
690
+ context "destroy prevention" do
691
+ it "can be destroyed when pending" do
692
+ shipment = create(:shipment, state: "pending")
693
+ expect(shipment.destroy).to be_truthy
694
+ expect { shipment.reload }.to raise_error(ActiveRecord::RecordNotFound)
695
+ end
696
+
697
+ it "cannot be destroyed when ready" do
698
+ shipment = create(:shipment, state: "ready")
699
+ expect(shipment.destroy).to eq false
700
+ expect(shipment.errors.full_messages.join).to match /Cannot destroy/
701
+ expect { shipment.reload }.not_to raise_error
702
+ end
703
+
704
+ it "cannot be destroyed when shipped" do
705
+ shipment = create(:shipment, state: "shipped")
706
+ expect(shipment.destroy).to eq false
707
+ expect(shipment.errors.full_messages.join).to match /Cannot destroy/
708
+ expect { shipment.reload }.not_to raise_error
709
+ end
710
+
711
+ it "cannot be destroyed when canceled" do
712
+ shipment = create(:shipment, state: "canceled")
713
+ expect(shipment.destroy).to eq false
714
+ expect(shipment.errors.full_messages.join).to match /Cannot destroy/
715
+ expect { shipment.reload }.not_to raise_error
716
+ end
717
+ end
718
+
719
+ describe "#finalize!" do
720
+ let(:inventory_unit) { shipment.inventory_units.first }
721
+ let(:stock_item) { inventory_unit.variant.stock_items.find_by(stock_location: stock_location) }
722
+
723
+ before do
724
+ stock_item.set_count_on_hand(10)
725
+ stock_item.update_attributes!(backorderable: false)
726
+ end
727
+
728
+ subject { shipment.finalize! }
729
+
730
+ it "updates the associated inventory units" do
731
+ inventory_unit.update_columns(updated_at: 1.hour.ago)
732
+ expect { subject }.to change { inventory_unit.reload.updated_at }
733
+ end
734
+
735
+ it "unstocks the variant" do
736
+ expect { subject }.to change { stock_item.reload.count_on_hand }.from(10).to(9)
737
+ end
738
+
739
+ context "inventory unit already finalized" do
740
+ before do
741
+ inventory_unit.update_attributes!(pending: false)
742
+ end
743
+
744
+ it "doesn't update the associated inventory units" do
745
+ expect { subject }.to_not change { inventory_unit.reload.updated_at }
746
+ end
747
+
748
+ it "doesn't unstock the variant" do
749
+ expect { subject }.to_not change { stock_item.reload.count_on_hand }
750
+ end
751
+ end
752
+ end
753
+ end