solidus_core 1.1.0 → 1.1.1

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 (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,1482 @@
1
+ require 'spec_helper'
2
+
3
+ class FakeCalculator < Spree::Calculator
4
+ def compute(computable)
5
+ 5
6
+ end
7
+ end
8
+
9
+ describe Spree::Order, :type => :model do
10
+ let(:user) { stub_model(Spree::LegacyUser, :email => "spree@example.com") }
11
+ let(:order) { stub_model(Spree::Order, :user => user) }
12
+
13
+ before do
14
+ allow(Spree::LegacyUser).to receive_messages(:current => mock_model(Spree::LegacyUser, :id => 123))
15
+ end
16
+
17
+ context "#canceled_by" do
18
+ let(:admin_user) { create :admin_user }
19
+ let(:order) { create :order }
20
+
21
+ before do
22
+ allow(order).to receive(:cancel!)
23
+ end
24
+
25
+ subject { order.canceled_by(admin_user) }
26
+
27
+ it 'should cancel the order' do
28
+ expect(order).to receive(:cancel!)
29
+ subject
30
+ end
31
+
32
+ it 'should save canceler_id' do
33
+ subject
34
+ expect(order.reload.canceler_id).to eq(admin_user.id)
35
+ end
36
+
37
+ it 'should save canceled_at' do
38
+ subject
39
+ expect(order.reload.canceled_at).to_not be_nil
40
+ end
41
+
42
+ it 'should have canceler' do
43
+ subject
44
+ expect(order.reload.canceler).to eq(admin_user)
45
+ end
46
+ end
47
+
48
+ context "#create" do
49
+ let(:order) { Spree::Order.create }
50
+
51
+ it "should assign an order number" do
52
+ expect(order.number).not_to be_nil
53
+ end
54
+
55
+ it 'should create a randomized 22 character token' do
56
+ expect(order.guest_token.size).to eq(22)
57
+ end
58
+ end
59
+
60
+ context "creates shipments cost" do
61
+ let(:shipment) { double }
62
+
63
+ before { allow(order).to receive_messages shipments: [shipment] }
64
+
65
+ it "update and persist totals" do
66
+ expect(shipment).to receive :update_amounts
67
+ expect(order.updater).to receive :update_shipment_total
68
+ expect(order.updater).to receive :persist_totals
69
+
70
+ order.set_shipments_cost
71
+ end
72
+ end
73
+
74
+ context "insufficient_stock_lines" do
75
+ let(:line_item) { mock_model Spree::LineItem, :insufficient_stock? => true }
76
+
77
+ before { allow(order).to receive_messages(:line_items => [line_item]) }
78
+
79
+ it "should return line_item that has insufficient stock on hand" do
80
+ expect(order.insufficient_stock_lines.size).to eq(1)
81
+ expect(order.insufficient_stock_lines.include?(line_item)).to be true
82
+ end
83
+ end
84
+
85
+ describe '#ensure_line_item_variants_are_not_deleted' do
86
+ subject { order.ensure_line_item_variants_are_not_deleted }
87
+
88
+ let(:order) { create :order_with_line_items }
89
+
90
+ context 'when variant is destroyed' do
91
+ before do
92
+ allow(order).to receive(:restart_checkout_flow)
93
+ order.line_items.first.variant.destroy
94
+ end
95
+
96
+ it 'should restart checkout flow' do
97
+ expect(order).to receive(:restart_checkout_flow).once
98
+ subject
99
+ end
100
+
101
+ it 'should have error message' do
102
+ subject
103
+ expect(order.errors[:base]).to include(Spree.t(:deleted_variants_present))
104
+ end
105
+
106
+ it 'should be false' do
107
+ expect(subject).to be_falsey
108
+ end
109
+ end
110
+
111
+ context 'when no variants are destroyed' do
112
+ it 'should not restart checkout' do
113
+ expect(order).to receive(:restart_checkout_flow).never
114
+ subject
115
+ end
116
+
117
+ it 'should be true' do
118
+ expect(subject).to be_truthy
119
+ end
120
+ end
121
+ end
122
+
123
+ context "empty!" do
124
+ let!(:order) { create(:order) }
125
+
126
+ before do
127
+ create(:line_item, order: order)
128
+ create(:shipment, order: order)
129
+ create(:adjustment, adjustable: order, order: order)
130
+ order.update!
131
+
132
+ # Make sure we are asserting changes
133
+ expect(order.line_items).not_to be_empty
134
+ expect(order.shipments).not_to be_empty
135
+ expect(order.adjustments).not_to be_empty
136
+ expect(order.item_total).not_to eq 0
137
+ expect(order.item_count).not_to eq 0
138
+ expect(order.shipment_total).not_to eq 0
139
+ expect(order.adjustment_total).not_to eq 0
140
+ end
141
+
142
+ it "clears out line items, adjustments and update totals" do
143
+ order.empty!
144
+ expect(order.line_items).to be_empty
145
+ expect(order.shipments).to be_empty
146
+ expect(order.adjustments).to be_empty
147
+ expect(order.item_total).to eq 0
148
+ expect(order.item_count).to eq 0
149
+ expect(order.shipment_total).to eq 0
150
+ expect(order.adjustment_total).to eq 0
151
+ end
152
+ end
153
+
154
+ context "#display_outstanding_balance" do
155
+ it "returns the value as a spree money" do
156
+ allow(order).to receive(:outstanding_balance) { 10.55 }
157
+ expect(order.display_outstanding_balance).to eq(Spree::Money.new(10.55))
158
+ end
159
+ end
160
+
161
+ context "#display_item_total" do
162
+ it "returns the value as a spree money" do
163
+ allow(order).to receive(:item_total) { 10.55 }
164
+ expect(order.display_item_total).to eq(Spree::Money.new(10.55))
165
+ end
166
+ end
167
+
168
+ context "#display_adjustment_total" do
169
+ it "returns the value as a spree money" do
170
+ order.adjustment_total = 10.55
171
+ expect(order.display_adjustment_total).to eq(Spree::Money.new(10.55))
172
+ end
173
+ end
174
+
175
+ context "#display_total" do
176
+ it "returns the value as a spree money" do
177
+ order.total = 10.55
178
+ expect(order.display_total).to eq(Spree::Money.new(10.55))
179
+ end
180
+ end
181
+
182
+ context "#currency" do
183
+ context "when object currency is ABC" do
184
+ before { order.currency = "ABC" }
185
+
186
+ it "returns the currency from the object" do
187
+ expect(order.currency).to eq("ABC")
188
+ end
189
+ end
190
+
191
+ context "when object currency is nil" do
192
+ before { order.currency = nil }
193
+
194
+ it "returns the globally configured currency" do
195
+ expect(order.currency).to eq("USD")
196
+ end
197
+ end
198
+ end
199
+
200
+ # Regression tests for #2179
201
+ context "#merge!" do
202
+ let(:variant) { create(:variant) }
203
+ let(:order_1) { Spree::Order.create }
204
+ let(:order_2) { Spree::Order.create }
205
+
206
+ it "destroys the other order" do
207
+ order_1.merge!(order_2)
208
+ expect { order_2.reload }.to raise_error(ActiveRecord::RecordNotFound)
209
+ end
210
+
211
+ context "user is provided" do
212
+ it "assigns user to new order" do
213
+ order_1.merge!(order_2, user)
214
+ expect(order_1.user).to eq user
215
+ end
216
+ end
217
+
218
+ context "merging together two orders with line items for the same variant" do
219
+ before do
220
+ order_1.contents.add(variant, 1)
221
+ order_2.contents.add(variant, 1)
222
+ end
223
+
224
+ specify do
225
+ order_1.merge!(order_2)
226
+ expect(order_1.line_items.count).to eq(1)
227
+
228
+ line_item = order_1.line_items.first
229
+ expect(line_item.quantity).to eq(2)
230
+ expect(line_item.variant_id).to eq(variant.id)
231
+ end
232
+
233
+ end
234
+
235
+ context "merging using extension-specific line_item_comparison_hooks" do
236
+ before do
237
+ Spree::Order.register_line_item_comparison_hook(:foos_match)
238
+ allow(Spree::Variant).to receive(:price_modifier_amount).and_return(0.00)
239
+ end
240
+
241
+ after do
242
+ # reset to avoid test pollution
243
+ Spree::Order.line_item_comparison_hooks = Set.new
244
+ end
245
+
246
+ context "2 equal line items" do
247
+ before do
248
+ @line_item_1 = order_1.contents.add(variant, 1, {foos: {}})
249
+ @line_item_2 = order_2.contents.add(variant, 1, {foos: {}})
250
+ end
251
+
252
+ specify do
253
+ expect(order_1).to receive(:foos_match).with(@line_item_1, kind_of(Hash)).and_return(true)
254
+ order_1.merge!(order_2)
255
+ expect(order_1.line_items.count).to eq(1)
256
+
257
+ line_item = order_1.line_items.first
258
+ expect(line_item.quantity).to eq(2)
259
+ expect(line_item.variant_id).to eq(variant.id)
260
+ end
261
+ end
262
+
263
+ context "2 different line items" do
264
+ before do
265
+ allow(order_1).to receive(:foos_match).and_return(false)
266
+
267
+ order_1.contents.add(variant, 1, {foos: {}})
268
+ order_2.contents.add(variant, 1, {foos: {bar: :zoo}})
269
+ end
270
+
271
+ specify do
272
+ order_1.merge!(order_2)
273
+ expect(order_1.line_items.count).to eq(2)
274
+
275
+ line_item = order_1.line_items.first
276
+ expect(line_item.quantity).to eq(1)
277
+ expect(line_item.variant_id).to eq(variant.id)
278
+
279
+ line_item = order_1.line_items.last
280
+ expect(line_item.quantity).to eq(1)
281
+ expect(line_item.variant_id).to eq(variant.id)
282
+ end
283
+ end
284
+ end
285
+
286
+ context "merging together two orders with different line items" do
287
+ let(:variant_2) { create(:variant) }
288
+
289
+ before do
290
+ order_1.contents.add(variant, 1)
291
+ order_2.contents.add(variant_2, 1)
292
+ end
293
+
294
+ specify do
295
+ order_1.merge!(order_2)
296
+ line_items = order_1.line_items.reload
297
+ expect(line_items.count).to eq(2)
298
+
299
+ expect(order_1.item_count).to eq 2
300
+ expect(order_1.item_total).to eq line_items.map(&:amount).sum
301
+
302
+ # No guarantee on ordering of line items, so we do this:
303
+ expect(line_items.pluck(:quantity)).to match_array([1, 1])
304
+ expect(line_items.pluck(:variant_id)).to match_array([variant.id, variant_2.id])
305
+ end
306
+ end
307
+ end
308
+
309
+ context "add_update_hook" do
310
+ before do
311
+ Spree::Order.class_eval do
312
+ register_update_hook :add_awesome_sauce
313
+ end
314
+ end
315
+
316
+ after do
317
+ Spree::Order.update_hooks = Set.new
318
+ end
319
+
320
+ it "calls hook during update" do
321
+ order = create(:order)
322
+ expect(order).to receive(:add_awesome_sauce)
323
+ order.update!
324
+ end
325
+
326
+ it "calls hook during finalize" do
327
+ order = create(:order)
328
+ expect(order).to receive(:add_awesome_sauce)
329
+ order.finalize!
330
+ end
331
+ end
332
+
333
+ context "ensure shipments will be updated" do
334
+ before do
335
+ Spree::Shipment.create!(order: order)
336
+ end
337
+
338
+ ['payment', 'confirm'].each do |order_state|
339
+ context "when ther order is in the #{order_state} state" do
340
+ before do
341
+ order.state = order_state
342
+ order.shipments.create!
343
+ end
344
+
345
+ it "destroys current shipments" do
346
+ order.ensure_updated_shipments
347
+ expect(order.shipments).to be_empty
348
+ end
349
+
350
+ it "puts order back in address state" do
351
+ order.ensure_updated_shipments
352
+ expect(order.state).to eql "cart"
353
+ end
354
+
355
+ it "resets shipment_total" do
356
+ order.update_column(:shipment_total, 5)
357
+ order.ensure_updated_shipments
358
+ expect(order.shipment_total).to eq(0)
359
+ end
360
+
361
+ it "does nothing if any shipments are ready" do
362
+ shipment = create(:shipment, order: subject, state: "ready")
363
+ expect { subject.ensure_updated_shipments }.not_to change { subject.reload.shipments }
364
+ expect { shipment.reload }.not_to raise_error
365
+ end
366
+
367
+ it "does nothing if any shipments are shipped" do
368
+ shipment = create(:shipment, order: subject, state: "shipped")
369
+ expect { subject.ensure_updated_shipments }.not_to change { subject.reload.shipments }
370
+ expect { shipment.reload }.not_to raise_error
371
+ end
372
+ end
373
+
374
+ end
375
+
376
+ context 'when the order is in address state' do
377
+ before do
378
+ order.state = 'address'
379
+ order.shipments.create!
380
+ end
381
+
382
+ it "destroys current shipments" do
383
+ order.ensure_updated_shipments
384
+ expect(order.shipments).to be_empty
385
+ end
386
+
387
+ it "resets shipment_total" do
388
+ order.update_column(:shipment_total, 5)
389
+ order.ensure_updated_shipments
390
+ expect(order.shipment_total).to eq(0)
391
+ end
392
+
393
+ it "puts the order in the cart state" do
394
+ order.ensure_updated_shipments
395
+ expect(order.state).to eq "cart"
396
+ end
397
+ end
398
+
399
+ context 'when the order is completed' do
400
+ before do
401
+ order.state = 'complete'
402
+ order.completed_at = Time.now
403
+ order.update_column(:shipment_total, 5)
404
+ order.shipments.create!
405
+ end
406
+
407
+ it "does not destroy the current shipments" do
408
+ expect {
409
+ order.ensure_updated_shipments
410
+ }.not_to change { order.shipments }
411
+ end
412
+
413
+ it "does not reset the shipment total" do
414
+ expect {
415
+ order.ensure_updated_shipments
416
+ }.not_to change { order.shipment_total }
417
+ end
418
+
419
+ it "does not put the order back in the address state" do
420
+ expect {
421
+ order.ensure_updated_shipments
422
+ }.not_to change { order.state }
423
+ end
424
+ end
425
+
426
+ context "except when order is completed, that's OrderInventory job" do
427
+ it "doesn't touch anything" do
428
+ allow(order).to receive_messages completed?: true
429
+ order.update_column(:shipment_total, 5)
430
+ order.shipments.create!
431
+
432
+ expect {
433
+ order.ensure_updated_shipments
434
+ }.not_to change { order.shipment_total }
435
+
436
+ expect {
437
+ order.ensure_updated_shipments
438
+ }.not_to change { order.shipments }
439
+
440
+ expect {
441
+ order.ensure_updated_shipments
442
+ }.not_to change { order.state }
443
+ end
444
+ end
445
+
446
+ end
447
+
448
+ describe "#tax_address" do
449
+ before { Spree::Config[:tax_using_ship_address] = tax_using_ship_address }
450
+ subject { order.tax_address }
451
+
452
+ context "when tax_using_ship_address is true" do
453
+ let(:tax_using_ship_address) { true }
454
+
455
+ it 'returns ship_address' do
456
+ expect(subject).to eq(order.ship_address)
457
+ end
458
+ end
459
+
460
+ context "when tax_using_ship_address is not true" do
461
+ let(:tax_using_ship_address) { false }
462
+
463
+ it "returns bill_address" do
464
+ expect(subject).to eq(order.bill_address)
465
+ end
466
+ end
467
+ end
468
+
469
+ describe "#restart_checkout_flow" do
470
+ context "when in cart state" do
471
+ let(:order) { create(:order_with_totals, state: "cart") }
472
+
473
+ it "remains in cart state" do
474
+ expect { order.restart_checkout_flow }.not_to change { order.state }
475
+ end
476
+ end
477
+ it "updates the state column to the first checkout_steps value" do
478
+ order = create(:order_with_totals, state: "delivery")
479
+ expect(order.checkout_steps).to eql ["address", "delivery", "confirm", "complete"]
480
+ expect{ order.restart_checkout_flow }.to change{order.state}.from("delivery").to("address")
481
+ end
482
+
483
+ context "without line items" do
484
+ it "updates the state column to cart" do
485
+ order = create(:order, state: "delivery")
486
+ expect{ order.restart_checkout_flow }.to change{order.state}.from("delivery").to("cart")
487
+ end
488
+ end
489
+ end
490
+
491
+ # Regression tests for #4072
492
+ context "#state_changed" do
493
+ let(:order) { FactoryGirl.create(:order) }
494
+
495
+ it "logs state changes" do
496
+ order.update_column(:payment_state, 'balance_due')
497
+ order.payment_state = 'paid'
498
+ expect(order.state_changes).to be_empty
499
+ order.state_changed('payment')
500
+ state_change = order.state_changes.find_by(:name => 'payment')
501
+ expect(state_change.previous_state).to eq('balance_due')
502
+ expect(state_change.next_state).to eq('paid')
503
+ end
504
+
505
+ it "does not do anything if state does not change" do
506
+ order.update_column(:payment_state, 'balance_due')
507
+ expect(order.state_changes).to be_empty
508
+ order.state_changed('payment')
509
+ expect(order.state_changes).to be_empty
510
+ end
511
+ end
512
+
513
+ # Regression test for #4199
514
+ context "#available_payment_methods" do
515
+ it "includes frontend payment methods" do
516
+ payment_method = Spree::PaymentMethod.create!({
517
+ :name => "Fake",
518
+ :active => true,
519
+ :display_on => "front_end",
520
+ })
521
+ expect(order.available_payment_methods).to include(payment_method)
522
+ end
523
+
524
+ it "includes 'both' payment methods" do
525
+ payment_method = Spree::PaymentMethod.create!({
526
+ :name => "Fake",
527
+ :active => true,
528
+ :display_on => "both",
529
+ })
530
+ expect(order.available_payment_methods).to include(payment_method)
531
+ end
532
+
533
+ it "does not include a payment method twice if display_on is blank" do
534
+ payment_method = Spree::PaymentMethod.create!({
535
+ :name => "Fake",
536
+ :active => true,
537
+ :display_on => "both",
538
+ })
539
+ expect(order.available_payment_methods.count).to eq(1)
540
+ expect(order.available_payment_methods).to include(payment_method)
541
+ end
542
+
543
+ context 'when the order has a store' do
544
+ let(:order) { create(:order) }
545
+
546
+ let!(:store_with_payment_methods) do
547
+ create(:store,
548
+ payment_methods: [payment_method_with_store],
549
+ )
550
+ end
551
+ let!(:payment_method_with_store) { create(:payment_method) }
552
+ let!(:store_without_payment_methods) { create(:store) }
553
+ let!(:payment_method_without_store) { create(:payment_method) }
554
+
555
+ context 'when the store has payment methods' do
556
+ before { order.update_attributes!(store: store_with_payment_methods) }
557
+
558
+ it 'returns only the matching payment methods for that store' do
559
+ expect(order.available_payment_methods).to match_array(
560
+ [payment_method_with_store]
561
+ )
562
+ end
563
+ end
564
+
565
+ context 'when the store does not have payment methods' do
566
+ before { order.update_attributes!(store: store_without_payment_methods) }
567
+
568
+ it 'returns all matching payment methods regardless of store' do
569
+ expect(order.available_payment_methods).to match_array(
570
+ [payment_method_with_store, payment_method_without_store]
571
+ )
572
+ end
573
+ end
574
+ end
575
+ end
576
+
577
+ context "#apply_free_shipping_promotions" do
578
+ it "calls out to the FreeShipping promotion handler" do
579
+ shipment = double('Shipment')
580
+ allow(order).to receive_messages :shipments => [shipment]
581
+ expect(Spree::PromotionHandler::FreeShipping).to receive(:new).and_return(handler = double)
582
+ expect(handler).to receive(:activate)
583
+
584
+ expect(Spree::ItemAdjustments).to receive(:new).with(shipment).and_return(adjuster = double)
585
+ expect(adjuster).to receive(:update)
586
+
587
+ expect(order.updater).to receive(:update_shipment_total)
588
+ expect(order.updater).to receive(:persist_totals)
589
+ order.apply_free_shipping_promotions
590
+ end
591
+ end
592
+
593
+
594
+ context "#products" do
595
+ before :each do
596
+ @variant1 = mock_model(Spree::Variant, :product => "product1")
597
+ @variant2 = mock_model(Spree::Variant, :product => "product2")
598
+ @line_items = [mock_model(Spree::LineItem, :product => "product1", :variant => @variant1, :variant_id => @variant1.id, :quantity => 1),
599
+ mock_model(Spree::LineItem, :product => "product2", :variant => @variant2, :variant_id => @variant2.id, :quantity => 2)]
600
+ allow(order).to receive_messages(:line_items => @line_items)
601
+ end
602
+
603
+ it "contains?" do
604
+ expect(order.contains?(@variant1)).to be true
605
+ end
606
+
607
+ it "gets the quantity of a given variant" do
608
+ expect(order.quantity_of(@variant1)).to eq(1)
609
+
610
+ @variant3 = mock_model(Spree::Variant, :product => "product3")
611
+ expect(order.quantity_of(@variant3)).to eq(0)
612
+ end
613
+
614
+ it "can find a line item matching a given variant" do
615
+ expect(order.find_line_item_by_variant(@variant1)).not_to be_nil
616
+ expect(order.find_line_item_by_variant(mock_model(Spree::Variant))).to be_nil
617
+ end
618
+
619
+ context "match line item with options" do
620
+ before do
621
+ Spree::Order.register_line_item_comparison_hook(:foos_match)
622
+ end
623
+
624
+ after do
625
+ # reset to avoid test pollution
626
+ Spree::Order.line_item_comparison_hooks = Set.new
627
+ end
628
+
629
+ it "matches line item when options match" do
630
+ allow(order).to receive(:foos_match).and_return(true)
631
+ expect(order.line_item_options_match(@line_items.first, {foos: {bar: :zoo}})).to be true
632
+ end
633
+
634
+ it "does not match line item without options" do
635
+ allow(order).to receive(:foos_match).and_return(false)
636
+ expect(order.line_item_options_match(@line_items.first, {})).to be false
637
+ end
638
+ end
639
+ end
640
+
641
+ context "#generate_order_number" do
642
+ context "when no configure" do
643
+ let(:default_length) { Spree::Order::ORDER_NUMBER_LENGTH + Spree::Order::ORDER_NUMBER_PREFIX.length }
644
+ subject(:order_number) { order.generate_order_number }
645
+
646
+ describe '#class' do
647
+ subject { super().class }
648
+ it { is_expected.to eq String }
649
+ end
650
+
651
+ describe '#length' do
652
+ subject { super().length }
653
+ it { is_expected.to eq default_length }
654
+ end
655
+ it { is_expected.to match /^#{Spree::Order::ORDER_NUMBER_PREFIX}/ }
656
+ end
657
+
658
+ context "when length option is 5" do
659
+ let(:option_length) { 5 + Spree::Order::ORDER_NUMBER_PREFIX.length }
660
+ it "should be option length for order number" do
661
+ expect(order.generate_order_number(length: 5).length).to eq option_length
662
+ end
663
+ end
664
+
665
+ context "when letters option is true" do
666
+ it "generates order number include letter" do
667
+ expect(order.generate_order_number(length: 100, letters: true)).to match /[A-Z]/
668
+ end
669
+ end
670
+
671
+ context "when prefix option is 'P'" do
672
+ it "generates order number and it prefix is 'P'" do
673
+ expect(order.generate_order_number(prefix: 'P')).to match /^P/
674
+ end
675
+ end
676
+ end
677
+
678
+ context "#associate_user!" do
679
+ let!(:user) { FactoryGirl.create(:user) }
680
+
681
+ it "should associate a user with a persisted order" do
682
+ order = FactoryGirl.create(:order_with_line_items, created_by: nil)
683
+ order.user = nil
684
+ order.email = nil
685
+ order.associate_user!(user)
686
+ expect(order.user).to eq(user)
687
+ expect(order.email).to eq(user.email)
688
+ expect(order.created_by).to eq(user)
689
+
690
+ # verify that the changes we made were persisted
691
+ order.reload
692
+ expect(order.user).to eq(user)
693
+ expect(order.email).to eq(user.email)
694
+ expect(order.created_by).to eq(user)
695
+ end
696
+
697
+ it "should not overwrite the created_by if it already is set" do
698
+ creator = create(:user)
699
+ order = FactoryGirl.create(:order_with_line_items, created_by: creator)
700
+
701
+ order.user = nil
702
+ order.email = nil
703
+ order.associate_user!(user)
704
+ expect(order.user).to eq(user)
705
+ expect(order.email).to eq(user.email)
706
+ expect(order.created_by).to eq(creator)
707
+
708
+ # verify that the changes we made were persisted
709
+ order.reload
710
+ expect(order.user).to eq(user)
711
+ expect(order.email).to eq(user.email)
712
+ expect(order.created_by).to eq(creator)
713
+ end
714
+
715
+ it "should associate a user with a non-persisted order" do
716
+ order = Spree::Order.new
717
+
718
+ expect do
719
+ order.associate_user!(user)
720
+ end.to change { [order.user, order.email] }.from([nil, nil]).to([user, user.email])
721
+ end
722
+
723
+ it "should not persist an invalid address" do
724
+ address = Spree::Address.new
725
+ order.user = nil
726
+ order.email = nil
727
+ order.ship_address = address
728
+ expect do
729
+ order.associate_user!(user)
730
+ end.not_to change { address.persisted? }.from(false)
731
+ end
732
+ end
733
+
734
+ context "#can_ship?" do
735
+ let(:order) { Spree::Order.create }
736
+
737
+ it "should be true for order in the 'complete' state" do
738
+ allow(order).to receive_messages(:complete? => true)
739
+ expect(order.can_ship?).to be true
740
+ end
741
+
742
+ it "should be true for order in the 'resumed' state" do
743
+ allow(order).to receive_messages(:resumed? => true)
744
+ expect(order.can_ship?).to be true
745
+ end
746
+
747
+ it "should be true for an order in the 'awaiting return' state" do
748
+ allow(order).to receive_messages(:awaiting_return? => true)
749
+ expect(order.can_ship?).to be true
750
+ end
751
+
752
+ it "should be true for an order in the 'returned' state" do
753
+ allow(order).to receive_messages(:returned? => true)
754
+ expect(order.can_ship?).to be true
755
+ end
756
+
757
+ it "should be false if the order is neither in the 'complete' nor 'resumed' state" do
758
+ allow(order).to receive_messages(:resumed? => false, :complete? => false)
759
+ expect(order.can_ship?).to be false
760
+ end
761
+ end
762
+
763
+ context "#completed?" do
764
+ it "should indicate if order is completed" do
765
+ order.completed_at = nil
766
+ expect(order.completed?).to be false
767
+
768
+ order.completed_at = Time.now
769
+ expect(order.completed?).to be true
770
+ end
771
+ end
772
+
773
+ context "#allow_checkout?" do
774
+ it "should be true if there are line_items in the order" do
775
+ allow(order).to receive_message_chain(:line_items, :count => 1)
776
+ expect(order.checkout_allowed?).to be true
777
+ end
778
+ it "should be false if there are no line_items in the order" do
779
+ allow(order).to receive_message_chain(:line_items, :count => 0)
780
+ expect(order.checkout_allowed?).to be false
781
+ end
782
+ end
783
+
784
+ context "#amount" do
785
+ before do
786
+ @order = create(:order, :user => user)
787
+ @order.line_items = [create(:line_item, :price => 1.0, :quantity => 2),
788
+ create(:line_item, :price => 1.0, :quantity => 1)]
789
+ end
790
+ it "should return the correct lum sum of items" do
791
+ expect(@order.amount).to eq(3.0)
792
+ end
793
+ end
794
+
795
+ context "#backordered?" do
796
+ it 'is backordered if one of the shipments is backordered' do
797
+ allow(order).to receive_messages(:shipments => [mock_model(Spree::Shipment, :backordered? => false),
798
+ mock_model(Spree::Shipment, :backordered? => true)])
799
+ expect(order).to be_backordered
800
+ end
801
+ end
802
+
803
+ context "#can_cancel?" do
804
+ it "should be false for completed order in the canceled state" do
805
+ order.state = 'canceled'
806
+ order.shipment_state = 'ready'
807
+ order.completed_at = Time.now
808
+ expect(order.can_cancel?).to be false
809
+ end
810
+
811
+ it "should be true for completed order with no shipment" do
812
+ order.state = 'complete'
813
+ order.shipment_state = nil
814
+ order.completed_at = Time.now
815
+ expect(order.can_cancel?).to be true
816
+ end
817
+ end
818
+
819
+ context "#tax_total" do
820
+ it "adds included tax and additional tax" do
821
+ allow(order).to receive_messages(:additional_tax_total => 10, :included_tax_total => 20)
822
+
823
+ expect(order.tax_total).to eq 30
824
+ end
825
+ end
826
+
827
+ # Regression test for #4923
828
+ context "locking" do
829
+ let(:order) { Spree::Order.create } # need a persisted in order to test locking
830
+
831
+ it 'can lock' do
832
+ expect { order.with_lock {} }.to_not raise_error
833
+ end
834
+ end
835
+
836
+ describe "#pre_tax_item_amount" do
837
+ it "sums all of the line items' pre tax amounts" do
838
+ subject.line_items = [
839
+ Spree::LineItem.new(price: 10, quantity: 2, pre_tax_amount: 5.0),
840
+ Spree::LineItem.new(price: 30, quantity: 1, pre_tax_amount: 14.0),
841
+ ]
842
+
843
+ expect(subject.pre_tax_item_amount).to eq 19.0
844
+ end
845
+ end
846
+
847
+ context "#refund_total" do
848
+ let(:order) { create(:order_with_line_items) }
849
+ let!(:payment) { create(:payment_with_refund, order: order) }
850
+ let!(:payment2) { create(:payment_with_refund, order: order) }
851
+
852
+ it "sums the reimbursment refunds on the order" do
853
+ expect(order.refund_total).to eq(10.0)
854
+ end
855
+ end
856
+
857
+ describe '#quantity' do
858
+ # Uses a persisted record, as the quantity is retrieved via a DB count
859
+ let(:order) { create :order_with_line_items, line_items_count: 3 }
860
+
861
+ it 'sums the quantity of all line items' do
862
+ expect(order.quantity).to eq 3
863
+ end
864
+ end
865
+
866
+ describe '#has_non_reimbursement_related_refunds?' do
867
+ subject do
868
+ order.has_non_reimbursement_related_refunds?
869
+ end
870
+
871
+ context 'no refunds exist' do
872
+ it { is_expected.to eq false }
873
+ end
874
+
875
+ context 'a non-reimbursement related refund exists' do
876
+ let(:order) { refund.payment.order }
877
+ let(:refund) { create(:refund, reimbursement_id: nil, amount: 5) }
878
+
879
+ it { is_expected.to eq true }
880
+ end
881
+
882
+ context 'an old-style refund exists' do
883
+ let(:order) { create(:order_ready_to_ship) }
884
+ let(:payment) { order.payments.first.tap { |p| allow(p).to receive_messages(profiles_supported: false) } }
885
+ let!(:refund_payment) {
886
+ build(:payment, amount: -1, order: order, state: 'completed', source: payment).tap do |p|
887
+ allow(p).to receive_messages(profiles_supported?: false)
888
+ p.save!
889
+ end
890
+ }
891
+
892
+ it { is_expected.to eq true }
893
+ end
894
+
895
+ context 'a reimbursement related refund exists' do
896
+ let(:order) { refund.payment.order }
897
+ let(:refund) { create(:refund, reimbursement_id: 123, amount: 5)}
898
+
899
+ it { is_expected.to eq false }
900
+ end
901
+ end
902
+
903
+ describe "#create_proposed_shipments" do
904
+ it "assigns the coordinator returned shipments to its shipments" do
905
+ shipment = build(:shipment)
906
+ allow_any_instance_of(Spree::Stock::Coordinator).to receive(:shipments).and_return([shipment])
907
+ subject.create_proposed_shipments
908
+ expect(subject.shipments).to eq [shipment]
909
+ end
910
+
911
+ it "raises an error if any shipments are ready" do
912
+ shipment = create(:shipment, order: subject, state: "ready")
913
+ expect {
914
+ expect {
915
+ subject.create_proposed_shipments
916
+ }.to raise_error(Spree::Order::CannotRebuildShipments)
917
+ }.not_to change { subject.reload.shipments }
918
+
919
+ expect { shipment.reload }.not_to raise_error
920
+ end
921
+
922
+ it "raises an error if any shipments are shipped" do
923
+ shipment = create(:shipment, order: subject, state: "shipped")
924
+ expect {
925
+ expect {
926
+ subject.create_proposed_shipments
927
+ }.to raise_error(Spree::Order::CannotRebuildShipments)
928
+ }.not_to change { subject.reload.shipments }
929
+
930
+ expect { shipment.reload }.not_to raise_error
931
+ end
932
+
933
+ context "unreturned exchange" do
934
+ let!(:first_shipment) do
935
+ create(:shipment, order: subject, state: first_shipment_state, created_at: 5.days.ago)
936
+ end
937
+ let!(:second_shipment) do
938
+ create(:shipment, order: subject, state: second_shipment_state, created_at: 5.days.ago)
939
+ end
940
+
941
+ context "all shipments are shipped" do
942
+ let(:first_shipment_state) { "shipped" }
943
+ let(:second_shipment_state) { "shipped" }
944
+
945
+ it "returns the shipments" do
946
+ subject.create_proposed_shipments
947
+ expect(subject.shipments).to match_array [first_shipment, second_shipment]
948
+ end
949
+ end
950
+ end
951
+ end
952
+
953
+ describe "#all_inventory_units_returned?" do
954
+ let(:order) { create(:order_with_line_items, line_items_count: 3) }
955
+
956
+ subject { order.all_inventory_units_returned? }
957
+
958
+ context "all inventory units are returned" do
959
+ before { order.inventory_units.update_all(state: 'returned') }
960
+
961
+ it "is true" do
962
+ expect(subject).to eq true
963
+ end
964
+ end
965
+
966
+ context "some inventory units are returned" do
967
+ before do
968
+ order.inventory_units.first.update_attribute(:state, 'returned')
969
+ end
970
+
971
+ it "is false" do
972
+ expect(subject).to eq false
973
+ end
974
+ end
975
+
976
+ context "no inventory units are returned" do
977
+ it "is false" do
978
+ expect(subject).to eq false
979
+ end
980
+ end
981
+ end
982
+
983
+ describe "#unreturned_exchange?" do
984
+ let(:order) { create(:order_with_line_items) }
985
+ subject { order.reload.unreturned_exchange? }
986
+
987
+ context "the order does not have a shipment" do
988
+ before { order.shipments.destroy_all }
989
+
990
+ it { is_expected.to be false }
991
+ end
992
+
993
+ context "shipment created after order" do
994
+ it { is_expected.to be false }
995
+ end
996
+
997
+ context "shipment created before order" do
998
+ before do
999
+ order.shipments.first.update_attributes!(created_at: order.created_at - 1.day)
1000
+ end
1001
+
1002
+ it { is_expected.to be true }
1003
+ end
1004
+ end
1005
+
1006
+ describe '.unreturned_exchange' do
1007
+ let(:order) { create(:order_with_line_items) }
1008
+ subject { described_class.unreturned_exchange }
1009
+
1010
+ it 'includes orders that have a shipment created prior to the order' do
1011
+ order.shipments.first.update_attributes!(created_at: order.created_at - 1.day)
1012
+ expect(subject).to include order
1013
+ end
1014
+
1015
+ it 'excludes orders that were created prior to their shipment' do
1016
+ expect(subject).not_to include order
1017
+ end
1018
+
1019
+ it 'excludes orders with no shipment' do
1020
+ order.shipments.destroy_all
1021
+ expect(subject).not_to include order
1022
+ end
1023
+ end
1024
+
1025
+ describe "#fully_discounted?" do
1026
+ let(:line_item) { Spree::LineItem.new(price: 10, quantity: 1) }
1027
+ let(:shipment) { Spree::Shipment.new(cost: 10) }
1028
+ let(:payment) { Spree::Payment.new(amount: 10) }
1029
+
1030
+ before do
1031
+ allow(order).to receive(:line_items) { [line_item] }
1032
+ allow(order).to receive(:shipments) { [shipment] }
1033
+ allow(order).to receive(:payments) { [payment] }
1034
+ end
1035
+
1036
+ context "the order had no inventory-related cost" do
1037
+ before do
1038
+ # discount the cost of the line items
1039
+ allow(order).to receive(:adjustment_total) { -5 }
1040
+ allow(line_item).to receive(:adjustment_total) { -5 }
1041
+
1042
+ # but leave some shipment payment amount
1043
+ allow(shipment).to receive(:adjustment_total) { 0 }
1044
+ end
1045
+
1046
+ it { expect(order.fully_discounted?).to eq true }
1047
+
1048
+ end
1049
+
1050
+ context "the order had inventory-related cost" do
1051
+ before do
1052
+ # partially discount the cost of the line item
1053
+ allow(order).to receive(:adjustment_total) { 0 }
1054
+ allow(line_item).to receive(:adjustment_total) { -5 }
1055
+
1056
+ # and partially discount the cost of the shipment so the total
1057
+ # discount matches the item total for test completeness
1058
+ allow(shipment).to receive(:adjustment_total) { -5 }
1059
+ end
1060
+
1061
+ it { expect(order.fully_discounted?).to eq false }
1062
+
1063
+ end
1064
+ end
1065
+
1066
+ context "store credit" do
1067
+ shared_examples "check total store credit from payments" do
1068
+ context "with valid payments" do
1069
+ let(:order) { payment.order }
1070
+ let!(:payment) { create(:store_credit_payment) }
1071
+ let!(:second_payment) { create(:store_credit_payment, order: order) }
1072
+
1073
+ subject { order }
1074
+
1075
+ it "returns the sum of the payment amounts" do
1076
+ expect(subject.total_applicable_store_credit).to eq (payment.amount + second_payment.amount)
1077
+ end
1078
+ end
1079
+
1080
+ context "without valid payments" do
1081
+ let(:order) { create(:order) }
1082
+
1083
+ subject { order }
1084
+
1085
+ it "returns 0" do
1086
+ expect(subject.total_applicable_store_credit).to be_zero
1087
+ end
1088
+ end
1089
+ end
1090
+
1091
+ describe "#add_store_credit_payments" do
1092
+ let(:order_total) { 500.00 }
1093
+
1094
+ before { create(:store_credit_payment_method) }
1095
+
1096
+ subject { order.add_store_credit_payments }
1097
+
1098
+ context "there is no store credit" do
1099
+ let(:order) { create(:order, total: order_total) }
1100
+
1101
+ context "there is a credit card payment" do
1102
+ let!(:cc_payment) { create(:payment, order: order, amount: order_total) }
1103
+
1104
+ before do
1105
+ # callbacks recalculate total based on line items
1106
+ # this ensures the total is what we expect
1107
+ order.update_column(:total, order_total)
1108
+ subject
1109
+ order.reload
1110
+ end
1111
+
1112
+ it "charges the outstanding balance to the credit card" do
1113
+ expect(order.errors.messages).to be_empty
1114
+ expect(order.payments.count).to eq 1
1115
+ expect(order.payments.first.source).to be_a(Spree::CreditCard)
1116
+ expect(order.payments.first.amount).to eq order_total
1117
+ end
1118
+ end
1119
+
1120
+ context "there are no other payments" do
1121
+ it "adds an error to the model" do
1122
+ expect(subject).to be false
1123
+ expect(order.errors.full_messages).to include(Spree.t("store_credit.errors.unable_to_fund"))
1124
+ end
1125
+ end
1126
+ end
1127
+
1128
+ context "there is enough store credit to pay for the entire order" do
1129
+ let(:store_credit) { create(:store_credit, amount: order_total) }
1130
+ let(:order) { create(:order_with_totals, user: store_credit.user, line_items_price: order_total).tap(&:update!) }
1131
+
1132
+ context "there are no other payments" do
1133
+ before do
1134
+ subject
1135
+ order.reload
1136
+ end
1137
+
1138
+ it "creates a store credit payment for the full amount" do
1139
+ expect(order.errors.messages).to be_empty
1140
+ expect(order.payments.count).to eq 1
1141
+ expect(order.payments.first).to be_store_credit
1142
+ expect(order.payments.first.amount).to eq order_total
1143
+ end
1144
+ end
1145
+
1146
+ context "there is a credit card payment" do
1147
+ it "invalidates the credit card payment" do
1148
+ cc_payment = create(:payment, order: order)
1149
+ expect { subject }.to change { cc_payment.reload.state }.to 'invalid'
1150
+ end
1151
+ end
1152
+ end
1153
+
1154
+ context "the available store credit is not enough to pay for the entire order" do
1155
+ let(:order_total) { 500 }
1156
+ let(:store_credit_total) { order_total - 100 }
1157
+ let(:store_credit) { create(:store_credit, amount: store_credit_total) }
1158
+ let(:order) { create(:order_with_totals, user: store_credit.user, line_items_price: order_total).tap(&:update!) }
1159
+
1160
+ context "there are no other payments" do
1161
+ it "adds an error to the model" do
1162
+ expect(subject).to be false
1163
+ expect(order.errors.full_messages).to include(Spree.t("store_credit.errors.unable_to_fund"))
1164
+ end
1165
+ end
1166
+
1167
+ context "there is a credit card payment" do
1168
+ let!(:cc_payment) { create(:payment, order: order, state: "checkout") }
1169
+
1170
+ before do
1171
+ subject
1172
+ end
1173
+
1174
+ it "charges the outstanding balance to the credit card" do
1175
+ expect(order.errors.messages).to be_empty
1176
+ expect(order.payments.count).to eq 2
1177
+ expect(order.payments.first.source).to be_a(Spree::CreditCard)
1178
+ expect(order.payments.first.amount).to eq 100
1179
+ end
1180
+
1181
+ # see associated comment in order_decorator#add_store_credit_payments
1182
+ context "the store credit is already in the pending state" do
1183
+ before do
1184
+ order.payments.store_credits.last.authorize!
1185
+ order.add_store_credit_payments
1186
+ end
1187
+
1188
+ it "charges the outstanding balance to the credit card" do
1189
+ expect(order.errors.messages).to be_empty
1190
+ expect(order.payments.count).to eq 2
1191
+ expect(order.payments.first.source).to be_a(Spree::CreditCard)
1192
+ expect(order.payments.first.amount).to eq 100
1193
+ end
1194
+ end
1195
+ end
1196
+ end
1197
+
1198
+ context "there are multiple store credits" do
1199
+ context "they have different credit type priorities" do
1200
+ let(:amount_difference) { 100 }
1201
+ let!(:primary_store_credit) { create(:store_credit, amount: (order_total - amount_difference)) }
1202
+ let!(:secondary_store_credit) { create(:store_credit, amount: order_total, user: primary_store_credit.user, credit_type: create(:secondary_credit_type)) }
1203
+ let(:order) { create(:order_with_totals, user: primary_store_credit.user, line_items_price: order_total).tap(&:update!) }
1204
+
1205
+ before do
1206
+ subject
1207
+ order.reload
1208
+ end
1209
+
1210
+ it "uses the primary store credit type over the secondary" do
1211
+ primary_payment = order.payments.detect{|x| x.source == primary_store_credit }
1212
+ secondary_payment = order.payments.detect{|x| x.source == secondary_store_credit }
1213
+
1214
+ expect(order.payments.size).to eq 2
1215
+ expect(primary_payment.source).to eq primary_store_credit
1216
+ expect(secondary_payment.source).to eq secondary_store_credit
1217
+ expect(primary_payment.amount).to eq(order_total - amount_difference)
1218
+ expect(secondary_payment.amount).to eq(amount_difference)
1219
+ end
1220
+ end
1221
+ end
1222
+ end
1223
+
1224
+ describe "#covered_by_store_credit" do
1225
+ context "order doesn't have an associated user" do
1226
+ subject { create(:order, user: nil) }
1227
+
1228
+ it "returns false" do
1229
+ expect(subject.covered_by_store_credit).to be false
1230
+ end
1231
+ end
1232
+
1233
+ context "order has an associated user" do
1234
+ let(:user) { create(:user) }
1235
+
1236
+ subject { create(:order, user: user) }
1237
+
1238
+ context "user has enough store credit to pay for the order" do
1239
+ before do
1240
+ allow(user).to receive_messages(total_available_store_credit: 10.0)
1241
+ allow(subject).to receive_messages(total: 5.0)
1242
+ end
1243
+
1244
+ it "returns true" do
1245
+ expect(subject.covered_by_store_credit).to be true
1246
+ end
1247
+ end
1248
+
1249
+ context "user does not have enough store credit to pay for the order" do
1250
+ before do
1251
+ allow(user).to receive_messages(total_available_store_credit: 0.0)
1252
+ allow(subject).to receive_messages(total: 5.0)
1253
+ end
1254
+
1255
+ it "returns false" do
1256
+ expect(subject.covered_by_store_credit).to be false
1257
+ end
1258
+ end
1259
+ end
1260
+ end
1261
+
1262
+ describe "#total_available_store_credit" do
1263
+ context "order does not have an associated user" do
1264
+ subject { create(:order, user: nil) }
1265
+
1266
+ it "returns 0" do
1267
+ expect(subject.total_available_store_credit).to be_zero
1268
+ end
1269
+ end
1270
+
1271
+ context "order has an associated user" do
1272
+ let(:user) { create(:user) }
1273
+ let(:available_store_credit) { 25.0 }
1274
+
1275
+ subject { create(:order, user: user) }
1276
+
1277
+ before do
1278
+ allow(user).to receive_messages(total_available_store_credit: available_store_credit)
1279
+ end
1280
+
1281
+ it "returns the user's available store credit" do
1282
+ expect(subject.total_available_store_credit).to eq available_store_credit
1283
+ end
1284
+ end
1285
+ end
1286
+
1287
+ describe "#order_total_after_store_credit" do
1288
+ let(:order_total) { 100.0 }
1289
+
1290
+ subject { create(:order, total: order_total) }
1291
+
1292
+ before do
1293
+ allow(subject).to receive_messages(total_applicable_store_credit: applicable_store_credit)
1294
+ end
1295
+
1296
+ context "order's user has store credits" do
1297
+ let(:applicable_store_credit) { 10.0 }
1298
+
1299
+ it "deducts the applicable store credit" do
1300
+ expect(subject.order_total_after_store_credit).to eq (order_total - applicable_store_credit)
1301
+ end
1302
+ end
1303
+
1304
+ context "order's user does not have any store credits" do
1305
+ let(:applicable_store_credit) { 0.0 }
1306
+
1307
+ it "returns the order total" do
1308
+ expect(subject.order_total_after_store_credit).to eq order_total
1309
+ end
1310
+ end
1311
+ end
1312
+
1313
+ describe "#total_applicable_store_credit" do
1314
+ context "order is in the confirm state" do
1315
+ before { order.update_attributes(state: 'confirm') }
1316
+ include_examples "check total store credit from payments"
1317
+ end
1318
+
1319
+ context "order is completed" do
1320
+ before { order.update_attributes(state: 'complete') }
1321
+ include_examples "check total store credit from payments"
1322
+ end
1323
+
1324
+ context "order is in any state other than confirm or complete" do
1325
+ context "the associated user has store credits" do
1326
+ let(:store_credit) { create(:store_credit) }
1327
+ let(:order) { create(:order, user: store_credit.user) }
1328
+
1329
+ subject { order }
1330
+
1331
+ context "the store credit is more than the order total" do
1332
+ let(:order_total) { store_credit.amount - 1 }
1333
+
1334
+ before { order.update_attributes(total: order_total) }
1335
+
1336
+ it "returns the order total" do
1337
+ expect(subject.total_applicable_store_credit).to eq order_total
1338
+ end
1339
+ end
1340
+
1341
+ context "the store credit is less than the order total" do
1342
+ let(:order_total) { store_credit.amount * 10 }
1343
+
1344
+ before { order.update_attributes(total: order_total) }
1345
+
1346
+ it "returns the store credit amount" do
1347
+ expect(subject.total_applicable_store_credit).to eq store_credit.amount
1348
+ end
1349
+ end
1350
+ end
1351
+
1352
+ context "the associated user does not have store credits" do
1353
+ let(:order) { create(:order) }
1354
+
1355
+ subject { order }
1356
+
1357
+ it "returns 0" do
1358
+ expect(subject.total_applicable_store_credit).to be_zero
1359
+ end
1360
+ end
1361
+
1362
+ context "the order does not have an associated user" do
1363
+ subject { create(:order, user: nil) }
1364
+
1365
+ it "returns 0" do
1366
+ expect(subject.total_applicable_store_credit).to be_zero
1367
+ end
1368
+ end
1369
+ end
1370
+ end
1371
+
1372
+ describe "#display_total_applicable_store_credit" do
1373
+ let(:total_applicable_store_credit) { 10.00 }
1374
+
1375
+ subject { create(:order) }
1376
+
1377
+ before { allow(subject).to receive_messages(total_applicable_store_credit: total_applicable_store_credit) }
1378
+
1379
+ it "returns a money instance" do
1380
+ expect(subject.display_total_applicable_store_credit).to be_a(Spree::Money)
1381
+ end
1382
+
1383
+ it "returns a negative amount" do
1384
+ expect(subject.display_total_applicable_store_credit.money.cents).to eq (total_applicable_store_credit * -100.0)
1385
+ end
1386
+ end
1387
+
1388
+ describe "#display_order_total_after_store_credit" do
1389
+ let(:order_total_after_store_credit) { 10.00 }
1390
+
1391
+ subject { create(:order) }
1392
+
1393
+ before { allow(subject).to receive_messages(order_total_after_store_credit: order_total_after_store_credit) }
1394
+
1395
+ it "returns a money instance" do
1396
+ expect(subject.display_order_total_after_store_credit).to be_a(Spree::Money)
1397
+ end
1398
+
1399
+ it "returns the order_total_after_store_credit amount" do
1400
+ expect(subject.display_order_total_after_store_credit.money.cents).to eq (order_total_after_store_credit * 100.0)
1401
+ end
1402
+ end
1403
+
1404
+ describe "#display_total_available_store_credit" do
1405
+ let(:total_available_store_credit) { 10.00 }
1406
+
1407
+ subject { create(:order) }
1408
+
1409
+ before { allow(subject).to receive_messages(total_available_store_credit: total_available_store_credit) }
1410
+
1411
+ it "returns a money instance" do
1412
+ expect(subject.display_total_available_store_credit).to be_a(Spree::Money)
1413
+ end
1414
+
1415
+ it "returns the total_available_store_credit amount" do
1416
+ expect(subject.display_total_available_store_credit.money.cents).to eq (total_available_store_credit * 100.0)
1417
+ end
1418
+ end
1419
+
1420
+ describe "#display_store_credit_remaining_after_capture" do
1421
+ let(:total_available_store_credit) { 10.00 }
1422
+ let(:total_applicable_store_credit) { 5.00 }
1423
+
1424
+ subject { create(:order) }
1425
+
1426
+ before do
1427
+ allow(subject).to receive_messages(total_available_store_credit: total_available_store_credit,
1428
+ total_applicable_store_credit: total_applicable_store_credit)
1429
+ end
1430
+
1431
+ it "returns a money instance" do
1432
+ expect(subject.display_store_credit_remaining_after_capture).to be_a(Spree::Money)
1433
+ end
1434
+
1435
+ it "returns all of the user's available store credit minus what's applied to the order amount" do
1436
+ amount_remaining = total_available_store_credit - total_applicable_store_credit
1437
+ expect(subject.display_store_credit_remaining_after_capture.money.cents).to eq (amount_remaining * 100.0)
1438
+ end
1439
+ end
1440
+
1441
+ context 'when not capturing at order completion' do
1442
+ let!(:store_credit_payment_method) do
1443
+ create(
1444
+ :store_credit_payment_method,
1445
+ auto_capture: false, # not capturing at completion time
1446
+ )
1447
+ end
1448
+
1449
+ describe '#after_cancel' do
1450
+ let(:user) { create(:user) }
1451
+ let!(:store_credit) do
1452
+ create(:store_credit, amount: 100, user: user)
1453
+ end
1454
+ let(:order) do
1455
+ create(
1456
+ :order_with_line_items,
1457
+ user: user,
1458
+ line_items_count: 1,
1459
+ # order will be $20 total:
1460
+ line_items_price: 10,
1461
+ shipment_cost: 10,
1462
+ )
1463
+ end
1464
+
1465
+ before do
1466
+ order.contents.advance
1467
+ order.complete!
1468
+ end
1469
+
1470
+ it 'releases the pending store credit authorization' do
1471
+ expect {
1472
+ order.cancel!
1473
+ }.to change {
1474
+ store_credit.reload.amount_authorized
1475
+ }.from(20).to(0)
1476
+
1477
+ expect(store_credit.amount_remaining).to eq 100
1478
+ end
1479
+ end
1480
+ end
1481
+ end
1482
+ end