solidus_core 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (228) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -0
  3. data/Rakefile +16 -0
  4. data/script/rails +9 -0
  5. data/solidus_core.gemspec +48 -0
  6. data/spec/fixtures/thinking-cat.jpg +0 -0
  7. data/spec/helpers/base_helper_spec.rb +173 -0
  8. data/spec/helpers/order_helper_spec.rb +12 -0
  9. data/spec/helpers/products_helper_spec.rb +208 -0
  10. data/spec/helpers/taxons_helper_spec.rb +17 -0
  11. data/spec/lib/calculated_adjustments_spec.rb +7 -0
  12. data/spec/lib/i18n_spec.rb +106 -0
  13. data/spec/lib/search/base_spec.rb +86 -0
  14. data/spec/lib/search/variant_spec.rb +112 -0
  15. data/spec/lib/spree/core/controller_helpers/auth_spec.rb +66 -0
  16. data/spec/lib/spree/core/controller_helpers/order_spec.rb +92 -0
  17. data/spec/lib/spree/core/controller_helpers/payment_parameters_spec.rb +80 -0
  18. data/spec/lib/spree/core/controller_helpers/search_spec.rb +17 -0
  19. data/spec/lib/spree/core/controller_helpers/store_spec.rb +16 -0
  20. data/spec/lib/spree/core/controller_helpers/strong_parameters_spec.rb +39 -0
  21. data/spec/lib/spree/core/current_store_spec.rb +36 -0
  22. data/spec/lib/spree/core/delegate_belongs_to_spec.rb +24 -0
  23. data/spec/lib/spree/core/importer/order_spec.rb +431 -0
  24. data/spec/lib/spree/core/role_configuration_spec.rb +156 -0
  25. data/spec/lib/spree/core/unreturned_item_charger_spec.rb +130 -0
  26. data/spec/lib/spree/core/validators/email_spec.rb +48 -0
  27. data/spec/lib/spree/localized_number_spec.rb +38 -0
  28. data/spec/lib/spree/migrations_spec.rb +36 -0
  29. data/spec/lib/spree/money_spec.rb +127 -0
  30. data/spec/lib/tasks/exchanges_spec.rb +231 -0
  31. data/spec/lib/tasks/migrations/copy_shipped_shipments_to_cartons_spec.rb +115 -0
  32. data/spec/lib/tasks/order_capturing_spec.rb +56 -0
  33. data/spec/mailers/carton_mailer_spec.rb +55 -0
  34. data/spec/mailers/order_mailer_spec.rb +135 -0
  35. data/spec/mailers/reimbursement_mailer_spec.rb +40 -0
  36. data/spec/mailers/test_mailer_spec.rb +15 -0
  37. data/spec/models/spree/ability_spec.rb +276 -0
  38. data/spec/models/spree/address_spec.rb +376 -0
  39. data/spec/models/spree/adjustment_reason_spec.rb +13 -0
  40. data/spec/models/spree/adjustment_spec.rb +169 -0
  41. data/spec/models/spree/app_configuration_spec.rb +24 -0
  42. data/spec/models/spree/asset_spec.rb +24 -0
  43. data/spec/models/spree/calculator/default_tax_spec.rb +127 -0
  44. data/spec/models/spree/calculator/flat_percent_item_total_spec.rb +25 -0
  45. data/spec/models/spree/calculator/flat_rate_spec.rb +47 -0
  46. data/spec/models/spree/calculator/flexi_rate_spec.rb +41 -0
  47. data/spec/models/spree/calculator/percent_on_line_item_spec.rb +15 -0
  48. data/spec/models/spree/calculator/price_sack_spec.rb +30 -0
  49. data/spec/models/spree/calculator/refunds/default_refund_amount_spec.rb +60 -0
  50. data/spec/models/spree/calculator/shipping/flat_percent_item_total_spec.rb +23 -0
  51. data/spec/models/spree/calculator/shipping/flat_rate_spec.rb +13 -0
  52. data/spec/models/spree/calculator/shipping/flexi_rate_spec.rb +52 -0
  53. data/spec/models/spree/calculator/shipping/per_item_spec.rb +20 -0
  54. data/spec/models/spree/calculator/shipping/price_sack_spec.rb +30 -0
  55. data/spec/models/spree/calculator/tiered_flat_rate_spec.rb +36 -0
  56. data/spec/models/spree/calculator/tiered_percent_spec.rb +47 -0
  57. data/spec/models/spree/calculator_spec.rb +36 -0
  58. data/spec/models/spree/carton_spec.rb +133 -0
  59. data/spec/models/spree/classification_spec.rb +93 -0
  60. data/spec/models/spree/concerns/display_money_spec.rb +43 -0
  61. data/spec/models/spree/concerns/ordered_property_value_list_spec.rb +25 -0
  62. data/spec/models/spree/concerns/user_address_book_spec.rb +332 -0
  63. data/spec/models/spree/concerns/user_methods_spec.rb +41 -0
  64. data/spec/models/spree/credit_card_spec.rb +341 -0
  65. data/spec/models/spree/customer_return_spec.rb +276 -0
  66. data/spec/models/spree/exchange_spec.rb +79 -0
  67. data/spec/models/spree/gateway/bogus_simple.rb +20 -0
  68. data/spec/models/spree/gateway/bogus_spec.rb +13 -0
  69. data/spec/models/spree/gateway_spec.rb +104 -0
  70. data/spec/models/spree/inventory_unit_spec.rb +307 -0
  71. data/spec/models/spree/item_adjustments_spec.rb +275 -0
  72. data/spec/models/spree/line_item_spec.rb +199 -0
  73. data/spec/models/spree/option_type_spec.rb +14 -0
  74. data/spec/models/spree/option_value_spec.rb +45 -0
  75. data/spec/models/spree/order/address_spec.rb +50 -0
  76. data/spec/models/spree/order/adjustments_spec.rb +27 -0
  77. data/spec/models/spree/order/callbacks_spec.rb +42 -0
  78. data/spec/models/spree/order/checkout_spec.rb +884 -0
  79. data/spec/models/spree/order/currency_updater_spec.rb +32 -0
  80. data/spec/models/spree/order/finalizing_spec.rb +110 -0
  81. data/spec/models/spree/order/payment_spec.rb +243 -0
  82. data/spec/models/spree/order/risk_assessment_spec.rb +68 -0
  83. data/spec/models/spree/order/state_machine_spec.rb +209 -0
  84. data/spec/models/spree/order/tax_spec.rb +84 -0
  85. data/spec/models/spree/order/totals_spec.rb +24 -0
  86. data/spec/models/spree/order/updating_spec.rb +18 -0
  87. data/spec/models/spree/order/validations_spec.rb +15 -0
  88. data/spec/models/spree/order_cancellations_spec.rb +120 -0
  89. data/spec/models/spree/order_capturing_spec.rb +150 -0
  90. data/spec/models/spree/order_contents_spec.rb +307 -0
  91. data/spec/models/spree/order_inventory_spec.rb +228 -0
  92. data/spec/models/spree/order_mutex_spec.rb +85 -0
  93. data/spec/models/spree/order_promotion_spec.rb +31 -0
  94. data/spec/models/spree/order_shipping_spec.rb +241 -0
  95. data/spec/models/spree/order_spec.rb +1482 -0
  96. data/spec/models/spree/order_stock_location_spec.rb +18 -0
  97. data/spec/models/spree/order_updater_spec.rb +283 -0
  98. data/spec/models/spree/payment_method/store_credit_spec.rb +294 -0
  99. data/spec/models/spree/payment_method_spec.rb +147 -0
  100. data/spec/models/spree/payment_spec.rb +1087 -0
  101. data/spec/models/spree/permission_sets/base_spec.rb +12 -0
  102. data/spec/models/spree/permission_sets/configuration_display.rb +82 -0
  103. data/spec/models/spree/permission_sets/configuration_management_spec.rb +50 -0
  104. data/spec/models/spree/permission_sets/dashboard_display_spec.rb +22 -0
  105. data/spec/models/spree/permission_sets/order_display_spec.rb +55 -0
  106. data/spec/models/spree/permission_sets/order_management_spec.rb +42 -0
  107. data/spec/models/spree/permission_sets/product_display_spec.rb +60 -0
  108. data/spec/models/spree/permission_sets/product_management_spec.rb +40 -0
  109. data/spec/models/spree/permission_sets/promotion_display_spec.rb +40 -0
  110. data/spec/models/spree/permission_sets/promotion_management_spec.rb +26 -0
  111. data/spec/models/spree/permission_sets/report_display_spec.rb +24 -0
  112. data/spec/models/spree/permission_sets/restricted_stock_display_spec.rb +41 -0
  113. data/spec/models/spree/permission_sets/restricted_stock_management_spec.rb +41 -0
  114. data/spec/models/spree/permission_sets/restricted_stock_transfer_display_spec.rb +50 -0
  115. data/spec/models/spree/permission_sets/restricted_stock_transfer_management_spec.rb +160 -0
  116. data/spec/models/spree/permission_sets/stock_display_spec.rb +24 -0
  117. data/spec/models/spree/permission_sets/stock_management_spec.rb +22 -0
  118. data/spec/models/spree/permission_sets/stock_transfer_display_spec.rb +24 -0
  119. data/spec/models/spree/permission_sets/stock_transfer_management_spec.rb +25 -0
  120. data/spec/models/spree/permission_sets/user_display_spec.rb +38 -0
  121. data/spec/models/spree/permission_sets/user_management_spec.rb +48 -0
  122. data/spec/models/spree/preference_spec.rb +80 -0
  123. data/spec/models/spree/preferences/configuration_spec.rb +30 -0
  124. data/spec/models/spree/preferences/preferable_spec.rb +294 -0
  125. data/spec/models/spree/preferences/scoped_store_spec.rb +60 -0
  126. data/spec/models/spree/preferences/static_model_preferences_spec.rb +78 -0
  127. data/spec/models/spree/preferences/statically_configurable_spec.rb +60 -0
  128. data/spec/models/spree/preferences/store_spec.rb +39 -0
  129. data/spec/models/spree/price_spec.rb +42 -0
  130. data/spec/models/spree/product/scopes_spec.rb +116 -0
  131. data/spec/models/spree/product_duplicator_spec.rb +103 -0
  132. data/spec/models/spree/product_filter_spec.rb +26 -0
  133. data/spec/models/spree/product_property_spec.rb +18 -0
  134. data/spec/models/spree/product_spec.rb +504 -0
  135. data/spec/models/spree/promotion/actions/create_adjustment_spec.rb +96 -0
  136. data/spec/models/spree/promotion/actions/create_item_adjustments_spec.rb +165 -0
  137. data/spec/models/spree/promotion/actions/create_quantity_adjustments_spec.rb +115 -0
  138. data/spec/models/spree/promotion/actions/free_shipping_spec.rb +40 -0
  139. data/spec/models/spree/promotion/rules/first_order_spec.rb +75 -0
  140. data/spec/models/spree/promotion/rules/first_repeat_purchase_since_spec.rb +69 -0
  141. data/spec/models/spree/promotion/rules/item_total_spec.rb +67 -0
  142. data/spec/models/spree/promotion/rules/nth_order_spec.rb +70 -0
  143. data/spec/models/spree/promotion/rules/one_use_per_user_spec.rb +42 -0
  144. data/spec/models/spree/promotion/rules/option_value_spec.rb +94 -0
  145. data/spec/models/spree/promotion/rules/product_spec.rb +143 -0
  146. data/spec/models/spree/promotion/rules/taxon_spec.rb +102 -0
  147. data/spec/models/spree/promotion/rules/user_logged_in_spec.rb +27 -0
  148. data/spec/models/spree/promotion/rules/user_spec.rb +37 -0
  149. data/spec/models/spree/promotion_builder_spec.rb +118 -0
  150. data/spec/models/spree/promotion_category_spec.rb +17 -0
  151. data/spec/models/spree/promotion_code/code_builder_spec.rb +79 -0
  152. data/spec/models/spree/promotion_code_spec.rb +187 -0
  153. data/spec/models/spree/promotion_handler/cart_spec.rb +130 -0
  154. data/spec/models/spree/promotion_handler/coupon_spec.rb +335 -0
  155. data/spec/models/spree/promotion_handler/free_shipping_spec.rb +47 -0
  156. data/spec/models/spree/promotion_handler/page_spec.rb +44 -0
  157. data/spec/models/spree/promotion_rule_spec.rb +28 -0
  158. data/spec/models/spree/promotion_spec.rb +776 -0
  159. data/spec/models/spree/refund_spec.rb +192 -0
  160. data/spec/models/spree/reimbursement/credit_spec.rb +36 -0
  161. data/spec/models/spree/reimbursement/reimbursement_type_engine_spec.rb +140 -0
  162. data/spec/models/spree/reimbursement/reimbursement_type_validator_spec.rb +83 -0
  163. data/spec/models/spree/reimbursement_performer_spec.rb +30 -0
  164. data/spec/models/spree/reimbursement_spec.rb +231 -0
  165. data/spec/models/spree/reimbursement_tax_calculator_spec.rb +51 -0
  166. data/spec/models/spree/reimbursement_type/credit_spec.rb +53 -0
  167. data/spec/models/spree/reimbursement_type/exchange_spec.rb +46 -0
  168. data/spec/models/spree/reimbursement_type/original_payment_spec.rb +107 -0
  169. data/spec/models/spree/reimbursement_type/store_credit_spec.rb +97 -0
  170. data/spec/models/spree/return_authorization_spec.rb +290 -0
  171. data/spec/models/spree/return_item/eligibility_validator/default_spec.rb +77 -0
  172. data/spec/models/spree/return_item/eligibility_validator/inventory_shipped_spec.rb +58 -0
  173. data/spec/models/spree/return_item/eligibility_validator/no_reimbursements_spec.rb +85 -0
  174. data/spec/models/spree/return_item/eligibility_validator/order_completed_spec.rb +32 -0
  175. data/spec/models/spree/return_item/eligibility_validator/rma_required_spec.rb +29 -0
  176. data/spec/models/spree/return_item/eligibility_validator/time_since_purchase_spec.rb +35 -0
  177. data/spec/models/spree/return_item/exchange_variant_eligibility/same_option_value_spec.rb +65 -0
  178. data/spec/models/spree/return_item/exchange_variant_eligibility/same_product_spec.rb +43 -0
  179. data/spec/models/spree/return_item_spec.rb +776 -0
  180. data/spec/models/spree/returns_calculator_spec.rb +14 -0
  181. data/spec/models/spree/shipment_spec.rb +753 -0
  182. data/spec/models/spree/shipping_calculator_spec.rb +45 -0
  183. data/spec/models/spree/shipping_manifest_spec.rb +94 -0
  184. data/spec/models/spree/shipping_method_spec.rb +88 -0
  185. data/spec/models/spree/shipping_rate_spec.rb +142 -0
  186. data/spec/models/spree/state_spec.rb +14 -0
  187. data/spec/models/spree/stock/availability_validator_spec.rb +83 -0
  188. data/spec/models/spree/stock/coordinator_spec.rb +116 -0
  189. data/spec/models/spree/stock/differentiator_spec.rb +39 -0
  190. data/spec/models/spree/stock/estimator_spec.rb +146 -0
  191. data/spec/models/spree/stock/inventory_unit_builder_spec.rb +38 -0
  192. data/spec/models/spree/stock/package_spec.rb +163 -0
  193. data/spec/models/spree/stock/packer_spec.rb +91 -0
  194. data/spec/models/spree/stock/prioritizer_spec.rb +125 -0
  195. data/spec/models/spree/stock/quantifier_spec.rb +115 -0
  196. data/spec/models/spree/stock/splitter/backordered_spec.rb +29 -0
  197. data/spec/models/spree/stock/splitter/base_spec.rb +21 -0
  198. data/spec/models/spree/stock/splitter/shipping_category_spec.rb +50 -0
  199. data/spec/models/spree/stock/splitter/weight_spec.rb +29 -0
  200. data/spec/models/spree/stock_item_spec.rb +444 -0
  201. data/spec/models/spree/stock_location_spec.rb +279 -0
  202. data/spec/models/spree/stock_movement_spec.rb +56 -0
  203. data/spec/models/spree/stock_transfer_spec.rb +290 -0
  204. data/spec/models/spree/store_credit_category_spec.rb +17 -0
  205. data/spec/models/spree/store_credit_event_spec.rb +314 -0
  206. data/spec/models/spree/store_credit_spec.rb +876 -0
  207. data/spec/models/spree/store_spec.rb +55 -0
  208. data/spec/models/spree/tax_category_spec.rb +27 -0
  209. data/spec/models/spree/tax_rate_spec.rb +378 -0
  210. data/spec/models/spree/taxon_spec.rb +74 -0
  211. data/spec/models/spree/taxonomy_spec.rb +18 -0
  212. data/spec/models/spree/tracker_spec.rb +21 -0
  213. data/spec/models/spree/transfer_item_spec.rb +264 -0
  214. data/spec/models/spree/unit_cancel_spec.rb +149 -0
  215. data/spec/models/spree/user_spec.rb +246 -0
  216. data/spec/models/spree/validations/db_maximum_length_validator_spec.rb +23 -0
  217. data/spec/models/spree/variant/scopes_spec.rb +55 -0
  218. data/spec/models/spree/variant_property_rule_condition_spec.rb +15 -0
  219. data/spec/models/spree/variant_property_rule_spec.rb +83 -0
  220. data/spec/models/spree/variant_property_rule_value_spec.rb +18 -0
  221. data/spec/models/spree/variant_spec.rb +601 -0
  222. data/spec/models/spree/zone_spec.rb +305 -0
  223. data/spec/spec_helper.rb +80 -0
  224. data/spec/support/big_decimal.rb +5 -0
  225. data/spec/support/concerns/default_price.rb +34 -0
  226. data/spec/support/dummy_ability.rb +4 -0
  227. data/spec/support/test_gateway.rb +2 -0
  228. metadata +242 -2
@@ -0,0 +1,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