solidus_core 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1 -0
  3. data/Gemfile +3 -0
  4. data/Rakefile +16 -0
  5. data/script/rails +9 -0
  6. data/solidus_core.gemspec +48 -0
  7. data/spec/fixtures/thinking-cat.jpg +0 -0
  8. data/spec/helpers/base_helper_spec.rb +173 -0
  9. data/spec/helpers/order_helper_spec.rb +12 -0
  10. data/spec/helpers/products_helper_spec.rb +220 -0
  11. data/spec/helpers/taxons_helper_spec.rb +17 -0
  12. data/spec/lib/calculated_adjustments_spec.rb +7 -0
  13. data/spec/lib/i18n_spec.rb +123 -0
  14. data/spec/lib/search/base_spec.rb +86 -0
  15. data/spec/lib/search/variant_spec.rb +92 -0
  16. data/spec/lib/spree/core/controller_helpers/auth_spec.rb +66 -0
  17. data/spec/lib/spree/core/controller_helpers/order_spec.rb +92 -0
  18. data/spec/lib/spree/core/controller_helpers/search_spec.rb +17 -0
  19. data/spec/lib/spree/core/controller_helpers/store_spec.rb +16 -0
  20. data/spec/lib/spree/core/controller_helpers/strong_parameters_spec.rb +39 -0
  21. data/spec/lib/spree/core/current_store_spec.rb +36 -0
  22. data/spec/lib/spree/core/delegate_belongs_to_spec.rb +22 -0
  23. data/spec/lib/spree/core/importer/order_spec.rb +431 -0
  24. data/spec/lib/spree/core/role_configuration_spec.rb +138 -0
  25. data/spec/lib/spree/core/validators/email_spec.rb +48 -0
  26. data/spec/lib/spree/localized_number_spec.rb +38 -0
  27. data/spec/lib/spree/migrations_spec.rb +36 -0
  28. data/spec/lib/spree/money_spec.rb +127 -0
  29. data/spec/lib/tasks/exchanges_spec.rb +231 -0
  30. data/spec/lib/tasks/migrations/copy_shipped_shipments_to_cartons_spec.rb +115 -0
  31. data/spec/lib/tasks/order_capturing_spec.rb +56 -0
  32. data/spec/mailers/carton_mailer_spec.rb +43 -0
  33. data/spec/mailers/order_mailer_spec.rb +122 -0
  34. data/spec/mailers/reimbursement_mailer_spec.rb +40 -0
  35. data/spec/mailers/test_mailer_spec.rb +15 -0
  36. data/spec/models/spree/ability_spec.rb +276 -0
  37. data/spec/models/spree/address_spec.rb +250 -0
  38. data/spec/models/spree/adjustment_reason_spec.rb +13 -0
  39. data/spec/models/spree/adjustment_spec.rb +177 -0
  40. data/spec/models/spree/app_configuration_spec.rb +20 -0
  41. data/spec/models/spree/asset_spec.rb +24 -0
  42. data/spec/models/spree/calculator/default_tax_spec.rb +127 -0
  43. data/spec/models/spree/calculator/flat_percent_item_total_spec.rb +25 -0
  44. data/spec/models/spree/calculator/flat_rate_spec.rb +47 -0
  45. data/spec/models/spree/calculator/flexi_rate_spec.rb +41 -0
  46. data/spec/models/spree/calculator/percent_on_line_item_spec.rb +15 -0
  47. data/spec/models/spree/calculator/price_sack_spec.rb +30 -0
  48. data/spec/models/spree/calculator/refunds/default_refund_amount_spec.rb +51 -0
  49. data/spec/models/spree/calculator/shipping/flat_percent_item_total_spec.rb +23 -0
  50. data/spec/models/spree/calculator/shipping/flat_rate_spec.rb +13 -0
  51. data/spec/models/spree/calculator/shipping/flexi_rate_spec.rb +52 -0
  52. data/spec/models/spree/calculator/shipping/per_item_spec.rb +20 -0
  53. data/spec/models/spree/calculator/shipping/price_sack_spec.rb +30 -0
  54. data/spec/models/spree/calculator/tiered_flat_rate_spec.rb +36 -0
  55. data/spec/models/spree/calculator/tiered_percent_spec.rb +47 -0
  56. data/spec/models/spree/calculator_spec.rb +36 -0
  57. data/spec/models/spree/carton_spec.rb +133 -0
  58. data/spec/models/spree/classification_spec.rb +15 -0
  59. data/spec/models/spree/concerns/display_money_spec.rb +43 -0
  60. data/spec/models/spree/concerns/user_methods_spec.rb +41 -0
  61. data/spec/models/spree/credit_card_spec.rb +334 -0
  62. data/spec/models/spree/customer_return_spec.rb +276 -0
  63. data/spec/models/spree/exchange_spec.rb +79 -0
  64. data/spec/models/spree/gateway/bogus_simple.rb +20 -0
  65. data/spec/models/spree/gateway/bogus_spec.rb +13 -0
  66. data/spec/models/spree/gateway_spec.rb +82 -0
  67. data/spec/models/spree/inventory_unit_spec.rb +307 -0
  68. data/spec/models/spree/item_adjustments_spec.rb +256 -0
  69. data/spec/models/spree/line_item_spec.rb +191 -0
  70. data/spec/models/spree/option_type_spec.rb +14 -0
  71. data/spec/models/spree/option_value_spec.rb +22 -0
  72. data/spec/models/spree/order/address_spec.rb +50 -0
  73. data/spec/models/spree/order/adjustments_spec.rb +39 -0
  74. data/spec/models/spree/order/callbacks_spec.rb +42 -0
  75. data/spec/models/spree/order/checkout_spec.rb +902 -0
  76. data/spec/models/spree/order/currency_updater_spec.rb +32 -0
  77. data/spec/models/spree/order/finalizing_spec.rb +111 -0
  78. data/spec/models/spree/order/payment_spec.rb +210 -0
  79. data/spec/models/spree/order/risk_assessment_spec.rb +68 -0
  80. data/spec/models/spree/order/state_machine_spec.rb +221 -0
  81. data/spec/models/spree/order/tax_spec.rb +84 -0
  82. data/spec/models/spree/order/totals_spec.rb +24 -0
  83. data/spec/models/spree/order/updating_spec.rb +18 -0
  84. data/spec/models/spree/order/validations_spec.rb +15 -0
  85. data/spec/models/spree/order_cancellations_spec.rb +120 -0
  86. data/spec/models/spree/order_capturing_spec.rb +116 -0
  87. data/spec/models/spree/order_contents_spec.rb +265 -0
  88. data/spec/models/spree/order_inventory_spec.rb +228 -0
  89. data/spec/models/spree/order_mutex_spec.rb +85 -0
  90. data/spec/models/spree/order_promotion_spec.rb +31 -0
  91. data/spec/models/spree/order_shipping_spec.rb +247 -0
  92. data/spec/models/spree/order_spec.rb +1412 -0
  93. data/spec/models/spree/order_stock_location_spec.rb +18 -0
  94. data/spec/models/spree/order_updater_spec.rb +299 -0
  95. data/spec/models/spree/payment_method/store_credit_spec.rb +294 -0
  96. data/spec/models/spree/payment_method_spec.rb +96 -0
  97. data/spec/models/spree/payment_spec.rb +1044 -0
  98. data/spec/models/spree/permission_sets/base_spec.rb +12 -0
  99. data/spec/models/spree/permission_sets/configuration_display.rb +82 -0
  100. data/spec/models/spree/permission_sets/configuration_management_spec.rb +50 -0
  101. data/spec/models/spree/permission_sets/dashboard_display_spec.rb +22 -0
  102. data/spec/models/spree/permission_sets/order_display_spec.rb +49 -0
  103. data/spec/models/spree/permission_sets/order_management_spec.rb +36 -0
  104. data/spec/models/spree/permission_sets/product_display_spec.rb +60 -0
  105. data/spec/models/spree/permission_sets/product_management_spec.rb +40 -0
  106. data/spec/models/spree/permission_sets/promotion_display_spec.rb +34 -0
  107. data/spec/models/spree/permission_sets/promotion_management_spec.rb +26 -0
  108. data/spec/models/spree/permission_sets/report_display_spec.rb +24 -0
  109. data/spec/models/spree/permission_sets/restricted_transfer_management_spec.rb +132 -0
  110. data/spec/models/spree/permission_sets/stock_display_spec.rb +26 -0
  111. data/spec/models/spree/permission_sets/stock_management_spec.rb +24 -0
  112. data/spec/models/spree/permission_sets/user_display_spec.rb +36 -0
  113. data/spec/models/spree/permission_sets/user_management_spec.rb +28 -0
  114. data/spec/models/spree/preference_spec.rb +80 -0
  115. data/spec/models/spree/preferences/configuration_spec.rb +30 -0
  116. data/spec/models/spree/preferences/preferable_spec.rb +294 -0
  117. data/spec/models/spree/preferences/scoped_store_spec.rb +58 -0
  118. data/spec/models/spree/preferences/static_model_preferences_spec.rb +78 -0
  119. data/spec/models/spree/preferences/statically_configurable_spec.rb +60 -0
  120. data/spec/models/spree/preferences/store_spec.rb +39 -0
  121. data/spec/models/spree/price_spec.rb +42 -0
  122. data/spec/models/spree/product/scopes_spec.rb +148 -0
  123. data/spec/models/spree/product_duplicator_spec.rb +103 -0
  124. data/spec/models/spree/product_filter_spec.rb +26 -0
  125. data/spec/models/spree/product_property_spec.rb +20 -0
  126. data/spec/models/spree/product_spec.rb +437 -0
  127. data/spec/models/spree/promotion/actions/create_adjustment_spec.rb +96 -0
  128. data/spec/models/spree/promotion/actions/create_item_adjustments_spec.rb +165 -0
  129. data/spec/models/spree/promotion/actions/create_quantity_adjustments_spec.rb +115 -0
  130. data/spec/models/spree/promotion/actions/free_shipping_spec.rb +40 -0
  131. data/spec/models/spree/promotion/rules/first_order_spec.rb +75 -0
  132. data/spec/models/spree/promotion/rules/item_total_spec.rb +67 -0
  133. data/spec/models/spree/promotion/rules/nth_order_spec.rb +70 -0
  134. data/spec/models/spree/promotion/rules/one_use_per_user_spec.rb +42 -0
  135. data/spec/models/spree/promotion/rules/option_value_spec.rb +94 -0
  136. data/spec/models/spree/promotion/rules/product_spec.rb +143 -0
  137. data/spec/models/spree/promotion/rules/taxon_spec.rb +102 -0
  138. data/spec/models/spree/promotion/rules/user_logged_in_spec.rb +27 -0
  139. data/spec/models/spree/promotion/rules/user_spec.rb +37 -0
  140. data/spec/models/spree/promotion_builder_spec.rb +118 -0
  141. data/spec/models/spree/promotion_category_spec.rb +17 -0
  142. data/spec/models/spree/promotion_code/code_builder_spec.rb +79 -0
  143. data/spec/models/spree/promotion_code_spec.rb +187 -0
  144. data/spec/models/spree/promotion_handler/cart_spec.rb +114 -0
  145. data/spec/models/spree/promotion_handler/coupon_spec.rb +335 -0
  146. data/spec/models/spree/promotion_handler/free_shipping_spec.rb +47 -0
  147. data/spec/models/spree/promotion_handler/page_spec.rb +44 -0
  148. data/spec/models/spree/promotion_rule_spec.rb +28 -0
  149. data/spec/models/spree/promotion_spec.rb +767 -0
  150. data/spec/models/spree/refund_spec.rb +204 -0
  151. data/spec/models/spree/reimbursement/credit_spec.rb +36 -0
  152. data/spec/models/spree/reimbursement/reimbursement_type_engine_spec.rb +140 -0
  153. data/spec/models/spree/reimbursement/reimbursement_type_validator_spec.rb +83 -0
  154. data/spec/models/spree/reimbursement_performer_spec.rb +30 -0
  155. data/spec/models/spree/reimbursement_spec.rb +231 -0
  156. data/spec/models/spree/reimbursement_tax_calculator_spec.rb +51 -0
  157. data/spec/models/spree/reimbursement_type/credit_spec.rb +53 -0
  158. data/spec/models/spree/reimbursement_type/exchange_spec.rb +46 -0
  159. data/spec/models/spree/reimbursement_type/original_payment_spec.rb +107 -0
  160. data/spec/models/spree/reimbursement_type/store_credit_spec.rb +97 -0
  161. data/spec/models/spree/return_authorization_spec.rb +290 -0
  162. data/spec/models/spree/return_item/eligibility_validator/default_spec.rb +77 -0
  163. data/spec/models/spree/return_item/eligibility_validator/inventory_shipped_spec.rb +58 -0
  164. data/spec/models/spree/return_item/eligibility_validator/no_reimbursements_spec.rb +85 -0
  165. data/spec/models/spree/return_item/eligibility_validator/order_completed_spec.rb +32 -0
  166. data/spec/models/spree/return_item/eligibility_validator/rma_required_spec.rb +29 -0
  167. data/spec/models/spree/return_item/eligibility_validator/time_since_purchase_spec.rb +35 -0
  168. data/spec/models/spree/return_item/exchange_variant_eligibility/same_option_value_spec.rb +65 -0
  169. data/spec/models/spree/return_item/exchange_variant_eligibility/same_product_spec.rb +43 -0
  170. data/spec/models/spree/return_item_spec.rb +775 -0
  171. data/spec/models/spree/returns_calculator_spec.rb +14 -0
  172. data/spec/models/spree/shipment_spec.rb +709 -0
  173. data/spec/models/spree/shipping_calculator_spec.rb +45 -0
  174. data/spec/models/spree/shipping_method_spec.rb +88 -0
  175. data/spec/models/spree/shipping_rate_spec.rb +142 -0
  176. data/spec/models/spree/state_spec.rb +14 -0
  177. data/spec/models/spree/stock/availability_validator_spec.rb +83 -0
  178. data/spec/models/spree/stock/coordinator_spec.rb +116 -0
  179. data/spec/models/spree/stock/differentiator_spec.rb +39 -0
  180. data/spec/models/spree/stock/estimator_spec.rb +146 -0
  181. data/spec/models/spree/stock/inventory_unit_builder_spec.rb +38 -0
  182. data/spec/models/spree/stock/package_spec.rb +163 -0
  183. data/spec/models/spree/stock/packer_spec.rb +91 -0
  184. data/spec/models/spree/stock/prioritizer_spec.rb +125 -0
  185. data/spec/models/spree/stock/quantifier_spec.rb +115 -0
  186. data/spec/models/spree/stock/splitter/backordered_spec.rb +29 -0
  187. data/spec/models/spree/stock/splitter/base_spec.rb +21 -0
  188. data/spec/models/spree/stock/splitter/shipping_category_spec.rb +50 -0
  189. data/spec/models/spree/stock/splitter/weight_spec.rb +29 -0
  190. data/spec/models/spree/stock_item_spec.rb +426 -0
  191. data/spec/models/spree/stock_location_spec.rb +279 -0
  192. data/spec/models/spree/stock_movement_spec.rb +56 -0
  193. data/spec/models/spree/stock_transfer_spec.rb +290 -0
  194. data/spec/models/spree/store_credit_category_spec.rb +17 -0
  195. data/spec/models/spree/store_credit_event_spec.rb +314 -0
  196. data/spec/models/spree/store_credit_spec.rb +876 -0
  197. data/spec/models/spree/store_spec.rb +55 -0
  198. data/spec/models/spree/tax_category_spec.rb +27 -0
  199. data/spec/models/spree/tax_rate_spec.rb +378 -0
  200. data/spec/models/spree/taxon_spec.rb +74 -0
  201. data/spec/models/spree/taxonomy_spec.rb +18 -0
  202. data/spec/models/spree/tracker_spec.rb +21 -0
  203. data/spec/models/spree/transfer_item_spec.rb +264 -0
  204. data/spec/models/spree/unit_cancel_spec.rb +148 -0
  205. data/spec/models/spree/user_spec.rb +223 -0
  206. data/spec/models/spree/validations/db_maximum_length_validator_spec.rb +23 -0
  207. data/spec/models/spree/variant/scopes_spec.rb +55 -0
  208. data/spec/models/spree/variant_spec.rb +546 -0
  209. data/spec/models/spree/zone_spec.rb +305 -0
  210. data/spec/spec_helper.rb +78 -0
  211. data/spec/support/big_decimal.rb +5 -0
  212. data/spec/support/concerns/default_price.rb +34 -0
  213. data/spec/support/dummy_ability.rb +4 -0
  214. data/spec/support/test_gateway.rb +2 -0
  215. metadata +229 -3
  216. data/lib/spree/testing_support/rspec-activemodel-mocks_patch.rb +0 -8
@@ -0,0 +1,228 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::OrderInventory, :type => :model do
4
+ let(:order) { create :completed_order_with_totals }
5
+ let(:line_item) { order.line_items.first }
6
+
7
+ subject { described_class.new(order, line_item) }
8
+
9
+ context "when order is missing inventory units" do
10
+ before { line_item.update_column(:quantity, 2) }
11
+
12
+ it 'creates the proper number of inventory units' do
13
+ subject.verify
14
+ expect(subject.inventory_units.count).to eq 2
15
+ end
16
+ end
17
+
18
+ context "#add_to_shipment" do
19
+ let(:shipment) { order.shipments.first }
20
+
21
+ context "order is not completed" do
22
+ before { allow(order).to receive_messages completed?: false }
23
+
24
+ it "doesn't unstock items" do
25
+ expect(shipment.stock_location).not_to receive(:unstock)
26
+ expect(subject.send(:add_to_shipment, shipment, 5)).to eq(5)
27
+ end
28
+ end
29
+
30
+ context "inventory units state" do
31
+ before { shipment.inventory_units.destroy_all }
32
+
33
+ it 'sets inventory_units state as per stock location availability' do
34
+ expect(shipment.stock_location).to receive(:fill_status).with(subject.variant, 5).and_return([3, 2])
35
+
36
+ expect(subject.send(:add_to_shipment, shipment, 5)).to eq(5)
37
+
38
+ units = shipment.inventory_units_for(subject.variant).group_by(&:state)
39
+ expect(units['backordered'].size).to eq(2)
40
+ expect(units['on_hand'].size).to eq(3)
41
+ end
42
+ end
43
+
44
+ context "store doesnt track inventory" do
45
+ let(:variant) { create(:variant) }
46
+
47
+ before { Spree::Config.track_inventory_levels = false }
48
+
49
+ it "creates only on hand inventory units" do
50
+ variant.stock_items.destroy_all
51
+
52
+ # The before_save callback in LineItem would verify inventory
53
+ line_item = order.contents.add variant, 1, shipment: shipment
54
+
55
+ units = shipment.inventory_units_for(line_item.variant)
56
+ expect(units.count).to eq 1
57
+ expect(units.first).to be_on_hand
58
+ end
59
+ end
60
+
61
+ context "variant doesnt track inventory" do
62
+ let(:variant) { create(:variant) }
63
+ before { variant.track_inventory = false }
64
+
65
+ it "creates only on hand inventory units" do
66
+ variant.stock_items.destroy_all
67
+
68
+ line_item = order.contents.add variant, 1
69
+ subject.verify(shipment)
70
+
71
+ units = shipment.inventory_units_for(line_item.variant)
72
+ expect(units.count).to eq 1
73
+ expect(units.first).to be_on_hand
74
+ end
75
+ end
76
+
77
+ it 'should create stock_movement' do
78
+ expect(subject.send(:add_to_shipment, shipment, 5)).to eq(5)
79
+
80
+ stock_item = shipment.stock_location.stock_item(subject.variant)
81
+ movement = stock_item.stock_movements.last
82
+ # movement.originator.should == shipment
83
+ expect(movement.quantity).to eq(-5)
84
+ end
85
+ end
86
+
87
+ context "#determine_target_shipment" do
88
+ let(:stock_location) { create :stock_location }
89
+ let(:variant) { line_item.variant }
90
+
91
+ before do
92
+ subject.verify
93
+
94
+ order.shipments.create(:stock_location_id => stock_location.id, :cost => 5)
95
+
96
+ shipped = order.shipments.create(:stock_location_id => order.shipments.first.stock_location.id, :cost => 10)
97
+ shipped.update_column(:state, 'shipped')
98
+ end
99
+
100
+ it 'should select first non-shipped shipment that already contains given variant' do
101
+ shipment = subject.send(:determine_target_shipment)
102
+ expect(shipment.shipped?).to be false
103
+ expect(shipment.inventory_units_for(variant)).not_to be_empty
104
+
105
+ expect(variant.stock_location_ids.include?(shipment.stock_location_id)).to be true
106
+ end
107
+
108
+ context "when no shipments already contain this varint" do
109
+ before do
110
+ subject.line_item.reload
111
+ subject.inventory_units.destroy_all
112
+ end
113
+
114
+ it 'selects first non-shipped shipment that leaves from same stock_location' do
115
+ shipment = subject.send(:determine_target_shipment)
116
+ shipment.reload
117
+ expect(shipment.shipped?).to be false
118
+ expect(shipment.inventory_units_for(variant)).to be_empty
119
+ expect(variant.stock_location_ids.include?(shipment.stock_location_id)).to be true
120
+ end
121
+ end
122
+ end
123
+
124
+ context 'when order has too many inventory units' do
125
+ before do
126
+ line_item.quantity = 3
127
+ line_item.save!
128
+
129
+ line_item.update_column(:quantity, 2)
130
+ subject.line_item.reload
131
+ end
132
+
133
+ it 'should be a messed up order' do
134
+ expect(order.shipments.first.inventory_units_for(line_item.variant).size).to eq(3)
135
+ expect(line_item.quantity).to eq(2)
136
+ end
137
+
138
+ it 'should decrease the number of inventory units' do
139
+ subject.verify
140
+ expect(subject.inventory_units.count).to eq 2
141
+ end
142
+
143
+ context '#remove_from_shipment' do
144
+ let(:shipment) { order.shipments.first }
145
+ let(:variant) { subject.variant }
146
+
147
+ context "order is not completed" do
148
+ before { allow(order).to receive_messages completed?: false }
149
+
150
+ it "doesn't restock items" do
151
+ expect(shipment.stock_location).not_to receive(:restock)
152
+ expect(subject.send(:remove_from_shipment, shipment, 1)).to eq(1)
153
+ end
154
+ end
155
+
156
+ it 'should create stock_movement' do
157
+ expect(subject.send(:remove_from_shipment, shipment, 1)).to eq(1)
158
+
159
+ stock_item = shipment.stock_location.stock_item(variant)
160
+ movement = stock_item.stock_movements.last
161
+ # movement.originator.should == shipment
162
+ expect(movement.quantity).to eq(1)
163
+ end
164
+
165
+ it 'should destroy backordered units first' do
166
+ allow(shipment).to receive_messages(inventory_units_for_item: [
167
+ mock_model(Spree::InventoryUnit, :variant_id => variant.id, :state => 'backordered'),
168
+ mock_model(Spree::InventoryUnit, :variant_id => variant.id, :state => 'on_hand'),
169
+ mock_model(Spree::InventoryUnit, :variant_id => variant.id, :state => 'backordered')
170
+ ])
171
+
172
+ expect(shipment.inventory_units_for_item[0]).to receive(:destroy)
173
+ expect(shipment.inventory_units_for_item[1]).not_to receive(:destroy)
174
+ expect(shipment.inventory_units_for_item[2]).to receive(:destroy)
175
+
176
+ expect(subject.send(:remove_from_shipment, shipment, 2)).to eq(2)
177
+ end
178
+
179
+ it 'should destroy unshipped units first' do
180
+ allow(shipment).to receive_messages(inventory_units_for_item: [
181
+ mock_model(Spree::InventoryUnit, :variant_id => variant.id, :state => 'shipped'),
182
+ mock_model(Spree::InventoryUnit, :variant_id => variant.id, :state => 'on_hand')
183
+ ])
184
+
185
+ expect(shipment.inventory_units_for_item[0]).not_to receive(:destroy)
186
+ expect(shipment.inventory_units_for_item[1]).to receive(:destroy)
187
+
188
+ expect(subject.send(:remove_from_shipment, shipment, 1)).to eq(1)
189
+ end
190
+
191
+ it 'only attempts to destroy as many units as are eligible, and return amount destroyed' do
192
+ allow(shipment).to receive_messages(inventory_units_for_item: [
193
+ mock_model(Spree::InventoryUnit, :variant_id => variant.id, :state => 'shipped'),
194
+ mock_model(Spree::InventoryUnit, :variant_id => variant.id, :state => 'on_hand')
195
+ ])
196
+
197
+ expect(shipment.inventory_units_for_item[0]).not_to receive(:destroy)
198
+ expect(shipment.inventory_units_for_item[1]).to receive(:destroy)
199
+
200
+ expect(subject.send(:remove_from_shipment, shipment, 1)).to eq(1)
201
+ end
202
+
203
+ it 'should destroy self if not inventory units remain' do
204
+ allow(shipment.inventory_units).to receive_messages(:count => 0)
205
+ expect(shipment).to receive(:destroy)
206
+
207
+ expect(subject.send(:remove_from_shipment, shipment, 1)).to eq(1)
208
+ end
209
+
210
+ context "inventory unit line item and variant points to different products" do
211
+ let(:different_line_item) { create(:line_item) }
212
+
213
+ let!(:different_inventory) do
214
+ shipment.set_up_inventory("on_hand", variant, order, different_line_item)
215
+ end
216
+
217
+ context "completed order" do
218
+ before { order.touch :completed_at }
219
+
220
+ it "removes only units that match both line item and variant" do
221
+ subject.send(:remove_from_shipment, shipment, shipment.inventory_units.count)
222
+ expect(different_inventory.reload).to be_persisted
223
+ end
224
+ end
225
+ end
226
+ end
227
+ end
228
+ end
@@ -0,0 +1,85 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::OrderMutex do
4
+ let(:order) { create(:order) }
5
+
6
+ context "without an existing lock" do
7
+ it "executes the block" do
8
+ expect { |b|
9
+ Spree::OrderMutex.with_lock!(order, &b)
10
+ }.to yield_control.once
11
+ end
12
+
13
+ it "releases the lock for subsequent calls" do
14
+ expect { |b|
15
+ Spree::OrderMutex.with_lock!(order, &b)
16
+ Spree::OrderMutex.with_lock!(order, &b)
17
+ }.to yield_control.twice
18
+ end
19
+
20
+ it "returns the value of the block" do
21
+ expect(Spree::OrderMutex.with_lock!(order) { 'yay for spree' }).to eq 'yay for spree'
22
+ end
23
+ end
24
+
25
+ context "with an existing lock on the same order" do
26
+ it "raises a LockFailed error and then releases the lock" do
27
+ Spree::OrderMutex.with_lock!(order) do
28
+ expect {
29
+ expect { |b|
30
+ Spree::OrderMutex.with_lock!(order, &b)
31
+ }.not_to yield_control
32
+ }.to raise_error(Spree::OrderMutex::LockFailed)
33
+ end
34
+
35
+ expect { |b|
36
+ Spree::OrderMutex.with_lock!(order, &b)
37
+ }.to yield_control.once
38
+ end
39
+ end
40
+
41
+ context "with an expired existing lock on the same order" do
42
+ around do |example|
43
+ Spree::OrderMutex.with_lock!(order) do
44
+ future = Spree::Config[:order_mutex_max_age].seconds.from_now + 1.second
45
+ Timecop.freeze(future) do
46
+ example.run
47
+ end
48
+ end
49
+ end
50
+
51
+ it "executes the block" do
52
+ expect { |b|
53
+ Spree::OrderMutex.with_lock!(order, &b)
54
+ }.to yield_control.once
55
+ end
56
+ end
57
+
58
+ context "with an existing lock on a different order" do
59
+ let(:order2) { create(:order) }
60
+
61
+ around do |example|
62
+ Spree::OrderMutex.with_lock!(order2) { example.run }
63
+ end
64
+
65
+ it "executes the block" do
66
+ expect { |b|
67
+ Spree::OrderMutex.with_lock!(order, &b)
68
+ }.to yield_control.once
69
+ end
70
+ end
71
+
72
+ context "when an unrelated RecordNotUnique error occurs" do
73
+ def raise_record_not_unique
74
+ raise ActiveRecord::RecordNotUnique.new("Testing")
75
+ end
76
+
77
+ it "does not rescue the unrelated error" do
78
+ expect {
79
+ Spree::OrderMutex.with_lock!(order) do
80
+ raise_record_not_unique
81
+ end
82
+ }.to raise_error(ActiveRecord::RecordNotUnique)
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::OrderPromotion do
4
+ subject do
5
+ order_promotion
6
+ end
7
+
8
+ let(:order_promotion) { build(:order_promotion) }
9
+
10
+ describe "promotion code presence error" do
11
+ subject do
12
+ order_promotion.valid?
13
+ order_promotion.errors[:promotion_code]
14
+ end
15
+
16
+ let(:order_promotion) { build(:order_promotion) }
17
+ let(:promotion) { order_promotion.promotion }
18
+
19
+ context "when the promotion does not have a code" do
20
+ it { is_expected.to be_blank }
21
+ end
22
+
23
+ context "when the promotion has a code" do
24
+ let!(:promotion_code) do
25
+ promotion.codes << build(:promotion_code, promotion: promotion)
26
+ end
27
+
28
+ it { is_expected.to include("can't be blank") }
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,247 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::OrderShipping do
4
+ let(:order) { create(:order_ready_to_ship, line_items_count: 1) }
5
+
6
+ def emails
7
+ ActionMailer::Base.deliveries
8
+ end
9
+
10
+ shared_examples 'shipment shipping' do
11
+
12
+ it "marks the inventory units as shipped" do
13
+ expect { subject }.to change { order.inventory_units.reload.map(&:state) }.from(['on_hand']).to(['shipped'])
14
+ end
15
+
16
+ it "creates a carton with the shipment's inventory units" do
17
+ expect { subject }.to change { order.cartons.count }.by(1)
18
+ expect(subject.inventory_units).to match_array(shipment.inventory_units)
19
+ end
20
+
21
+ describe "shipment email" do
22
+ before { with_test_mail { subject } }
23
+
24
+ it "should send a shipment email" do
25
+ expect(emails.size).to eq(1)
26
+ expect(emails.first.subject).to eq("#{order.store.name} Shipment Notification ##{order.number}")
27
+ end
28
+ end
29
+
30
+ it "updates the order shipment state" do
31
+ expect { subject }.to change { order.reload.shipment_state }.from('ready').to('shipped')
32
+ end
33
+
34
+ it "updates shipment.shipped_at" do
35
+ Timecop.freeze do |now|
36
+ expect { subject }.to change { shipment.shipped_at }.from(nil).to(now)
37
+ end
38
+ end
39
+
40
+ it "updates order.updated_at" do
41
+ future = 1.minute.from_now
42
+ expect do
43
+ Timecop.freeze(future) do
44
+ subject
45
+ end
46
+ end.to change { order.updated_at }.from(order.updated_at).to(future)
47
+ end
48
+
49
+ end
50
+
51
+ describe "#ship" do
52
+ subject do
53
+ order.shipping.ship(
54
+ inventory_units: inventory_units,
55
+ stock_location: stock_location,
56
+ address: address,
57
+ shipping_method: shipping_method,
58
+ )
59
+ end
60
+
61
+ let(:shipment) { order.shipments.to_a.first }
62
+ let(:inventory_units) { shipment.inventory_units }
63
+ let(:stock_location) { shipment.stock_location }
64
+ let(:address) { shipment.address }
65
+ let(:shipping_method) { shipment.shipping_method }
66
+
67
+ it_behaves_like 'shipment shipping'
68
+
69
+ context "with an external_number" do
70
+ subject do
71
+ order.shipping.ship(
72
+ inventory_units: inventory_units,
73
+ stock_location: stock_location,
74
+ address: address,
75
+ shipping_method: shipping_method,
76
+ external_number: 'some-external-number',
77
+ )
78
+ end
79
+
80
+ it "sets the external_number" do
81
+ expect(subject.external_number).to eq 'some-external-number'
82
+ end
83
+ end
84
+
85
+ context "with a tracking number" do
86
+ subject do
87
+ order.shipping.ship(
88
+ inventory_units: inventory_units,
89
+ stock_location: stock_location,
90
+ address: address,
91
+ shipping_method: shipping_method,
92
+ tracking_number: 'tracking-number',
93
+ )
94
+ end
95
+
96
+ it "sets the tracking-number" do
97
+ expect(subject.tracking).to eq 'tracking-number'
98
+ end
99
+ end
100
+
101
+ context "when told to suppress the mailer" do
102
+ before { with_test_mail { subject } }
103
+
104
+ subject do
105
+ order.shipping.ship(
106
+ inventory_units: inventory_units,
107
+ stock_location: stock_location,
108
+ address: address,
109
+ shipping_method: shipping_method,
110
+ suppress_mailer: true,
111
+ )
112
+ end
113
+
114
+ it "does not send a shipment email" do
115
+ expect(emails.size).to eq(0)
116
+ end
117
+ end
118
+ end
119
+
120
+ describe "#ship_shipment" do
121
+ subject { order.shipping.ship_shipment(shipment) }
122
+
123
+ let(:shipment) { order.shipments.to_a.first }
124
+
125
+ it_behaves_like 'shipment shipping'
126
+
127
+ context "when not all units are shippable" do
128
+ let(:order) { create(:order_ready_to_ship, line_items_count: 2) }
129
+ let(:shippable_line_item) { order.line_items.first }
130
+ let(:unshippable_line_item) { order.line_items.last }
131
+
132
+ before do
133
+ unshippable_line_item.inventory_units.each(&:cancel!)
134
+ end
135
+
136
+ it "only ships the shippable ones" do
137
+ expect(subject.inventory_units).to match_array(shippable_line_item.inventory_units)
138
+ end
139
+ end
140
+
141
+ context "when all units are canceled or shipped" do
142
+ let(:order) { create(:order_ready_to_ship, line_items_count: 2) }
143
+
144
+ before { Spree::OrderCancellations.new(order).short_ship([order.inventory_units.first]) }
145
+
146
+ it "updates the order shipment state" do
147
+ expect { subject }.to change { order.reload.shipment_state }.from('ready').to('shipped')
148
+ end
149
+ end
150
+
151
+ context "with an external_number" do
152
+ subject do
153
+ order.shipping.ship_shipment(
154
+ shipment,
155
+ external_number: 'some-external-number',
156
+ )
157
+ end
158
+
159
+ it "sets the external_number" do
160
+ expect(subject.external_number).to eq 'some-external-number'
161
+ end
162
+ end
163
+
164
+ context "with a tracking number" do
165
+ subject do
166
+ order.shipping.ship_shipment(
167
+ shipment,
168
+ tracking_number: 'tracking-number',
169
+ )
170
+ end
171
+
172
+ it "sets the tracking-number" do
173
+ expect(subject.tracking).to eq 'tracking-number'
174
+ end
175
+ end
176
+
177
+ # TODO: We can remove this once Shipment#ship! is called by
178
+ # OrderShipping#ship rather than vice versa
179
+ context "when the tracking number is already on the shipment" do
180
+ before do
181
+ shipment.update_attributes!(tracking: 'tracking-number')
182
+ end
183
+
184
+ it "sets the tracking-number" do
185
+ expect(subject.tracking).to eq 'tracking-number'
186
+ end
187
+ end
188
+
189
+ context "when the shipment has been partially shipped previously" do
190
+ let(:order) { create(:order_ready_to_ship, line_items_count: 2) }
191
+ let(:inventory_units) { shipment.inventory_units.to_a }
192
+ let(:shipped_inventory) { [inventory_units.first] }
193
+ let(:unshipped_inventory) { [inventory_units.last] }
194
+
195
+ before do
196
+ order.shipping.ship(
197
+ inventory_units: shipped_inventory,
198
+ stock_location: shipment.stock_location,
199
+ address: shipment.address,
200
+ shipping_method: shipment.shipping_method,
201
+ )
202
+ end
203
+
204
+ it "marks the inventory units as shipped" do
205
+ expect { subject }.to change { unshipped_inventory.map(&:reload).map(&:state) }.from(['on_hand']).to(['shipped'])
206
+ end
207
+
208
+ it "creates a carton with the shipment's inventory units" do
209
+ expect { subject }.to change { order.cartons.count }.by(1)
210
+ expect(subject.inventory_units).to match_array(unshipped_inventory)
211
+ end
212
+ end
213
+
214
+ context "when told to suppress the mailer" do
215
+ before { with_test_mail { subject } }
216
+
217
+ subject do
218
+ order.shipping.ship_shipment(
219
+ shipment,
220
+ suppress_mailer: true,
221
+ )
222
+ end
223
+
224
+ it "does not send a shipment email" do
225
+ expect(emails.size).to eq(0)
226
+ end
227
+ end
228
+
229
+ context "with stale inventory units (regression test)" do
230
+ let(:order) { FactoryGirl.create(:order_ready_to_ship, line_items_count: 1) }
231
+ let(:shipment) do
232
+ FactoryGirl.create(
233
+ :shipment,
234
+ order: order,
235
+ address: FactoryGirl.create(:address)
236
+ )
237
+ end
238
+
239
+ before { shipment.ready! }
240
+
241
+ it "updates the state to shipped" do
242
+ order.shipping.ship_shipment(shipment)
243
+ expect(shipment.reload.state).to eq "shipped"
244
+ end
245
+ end
246
+ end
247
+ end