solidus_core 2.0.3 → 2.1.0.beta1

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 (187) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +62 -3
  3. data/app/assets/javascripts/spree.js.coffee.erb +4 -1
  4. data/app/helpers/spree/base_helper.rb +7 -48
  5. data/app/models/spree/address.rb +5 -1
  6. data/app/models/spree/adjustment.rb +3 -3
  7. data/app/models/spree/app_configuration.rb +13 -0
  8. data/app/models/spree/calculator.rb +3 -2
  9. data/app/models/spree/calculator/default_tax.rb +6 -10
  10. data/app/models/spree/calculator/flat_percent_item_total.rb +0 -4
  11. data/app/models/spree/calculator/flat_rate.rb +0 -4
  12. data/app/models/spree/calculator/flexi_rate.rb +0 -4
  13. data/app/models/spree/calculator/free_shipping.rb +0 -3
  14. data/app/models/spree/calculator/percent_on_line_item.rb +0 -4
  15. data/app/models/spree/calculator/percent_per_item.rb +0 -4
  16. data/app/models/spree/calculator/price_sack.rb +0 -4
  17. data/app/models/spree/calculator/returns/default_refund_amount.rb +0 -3
  18. data/app/models/spree/calculator/shipping/flat_percent_item_total.rb +0 -4
  19. data/app/models/spree/calculator/shipping/flat_rate.rb +0 -4
  20. data/app/models/spree/calculator/shipping/flexi_rate.rb +0 -4
  21. data/app/models/spree/calculator/shipping/per_item.rb +0 -4
  22. data/app/models/spree/calculator/shipping/price_sack.rb +0 -4
  23. data/app/models/spree/calculator/tiered_flat_rate.rb +0 -4
  24. data/app/models/spree/calculator/tiered_percent.rb +0 -4
  25. data/app/models/spree/credit_card.rb +27 -14
  26. data/app/models/spree/gateway.rb +4 -0
  27. data/app/models/spree/inventory_unit.rb +2 -0
  28. data/app/models/spree/line_item.rb +31 -26
  29. data/app/models/spree/option_type.rb +0 -3
  30. data/app/models/spree/order.rb +28 -31
  31. data/app/models/spree/order/checkout.rb +0 -2
  32. data/app/models/spree/order_contents.rb +0 -45
  33. data/app/models/spree/order_merger.rb +6 -6
  34. data/app/models/spree/order_update_attributes.rb +0 -2
  35. data/app/models/spree/order_updater.rb +91 -13
  36. data/app/models/spree/payment.rb +9 -2
  37. data/app/models/spree/payment/processing.rb +15 -9
  38. data/app/models/spree/payment_method.rb +48 -5
  39. data/app/models/spree/price.rb +7 -9
  40. data/app/models/spree/product.rb +1 -25
  41. data/app/models/spree/promotion.rb +22 -14
  42. data/app/models/spree/promotion/actions/create_adjustment.rb +12 -1
  43. data/app/models/spree/promotion/actions/create_item_adjustments.rb +15 -1
  44. data/app/models/spree/promotion/actions/create_quantity_adjustments.rb +5 -3
  45. data/app/models/spree/promotion/actions/free_shipping.rb +14 -0
  46. data/app/models/spree/promotion/rules/taxon.rb +7 -2
  47. data/app/models/spree/promotion/rules/user_role.rb +43 -0
  48. data/app/models/spree/promotion_action.rb +19 -2
  49. data/app/models/spree/promotion_handler/coupon.rb +1 -4
  50. data/app/models/spree/promotion_handler/free_shipping.rb +22 -17
  51. data/app/models/spree/promotion_rule_role.rb +6 -0
  52. data/app/models/spree/property.rb +0 -3
  53. data/app/models/spree/return_authorization.rb +2 -0
  54. data/app/models/spree/shipment.rb +5 -21
  55. data/app/models/spree/shipping_method.rb +23 -2
  56. data/app/models/spree/shipping_rate.rb +3 -0
  57. data/app/models/spree/stock/estimator.rb +1 -1
  58. data/app/models/spree/stock_location.rb +3 -0
  59. data/app/models/spree/store.rb +7 -0
  60. data/app/models/spree/tax/item_adjuster.rb +27 -12
  61. data/app/models/spree/tax/order_adjuster.rb +2 -5
  62. data/app/models/spree/tax/tax_helpers.rb +4 -8
  63. data/app/models/spree/tax_rate.rb +1 -15
  64. data/app/models/spree/taxon.rb +0 -3
  65. data/app/models/spree/transfer_item.rb +1 -1
  66. data/app/models/spree/user_class_handle.rb +14 -9
  67. data/app/models/spree/variant/pricing_options.rb +1 -1
  68. data/app/models/spree/wallet/add_payment_sources_to_wallet.rb +1 -1
  69. data/app/models/spree/zone.rb +20 -13
  70. data/config/locales/en.yml +144 -62
  71. data/db/migrate/20120831092320_spree_one_two.rb +0 -7
  72. data/db/migrate/20150723224133_remove_unnecessary_indexes.rb +0 -2
  73. data/db/migrate/20160924135758_remove_is_default_from_prices.rb +5 -0
  74. data/db/migrate/20161009141333_remove_currency_from_line_items.rb +5 -0
  75. data/db/migrate/20161014221052_add_available_to_columns_and_remove_display_on_from_payment_methods.rb +28 -0
  76. data/db/migrate/20161123154034_add_available_to_users_and_remove_display_on_from_shipping_methods.rb +20 -0
  77. data/lib/generators/spree/custom_user/templates/authentication_helpers.rb.tt +4 -0
  78. data/lib/generators/spree/dummy/dummy_generator.rb +0 -2
  79. data/lib/spree/core.rb +0 -5
  80. data/lib/spree/core/controller_helpers/pricing.rb +2 -1
  81. data/lib/spree/core/engine.rb +14 -0
  82. data/lib/spree/core/version.rb +1 -1
  83. data/lib/spree/deprecation.rb +1 -1
  84. data/lib/spree/localized_number.rb +3 -2
  85. data/lib/spree/permission_sets/configuration_display.rb +0 -1
  86. data/lib/spree/permission_sets/configuration_management.rb +0 -1
  87. data/lib/spree/permission_sets/product_display.rb +0 -1
  88. data/lib/spree/permission_sets/product_management.rb +0 -1
  89. data/lib/spree/permission_sets/user_management.rb +2 -4
  90. data/lib/spree/permitted_attributes.rb +3 -2
  91. data/lib/spree/testing_support/capybara_ext.rb +0 -12
  92. data/lib/spree/testing_support/factories/address_factory.rb +1 -1
  93. data/lib/spree/testing_support/factories/line_item_factory.rb +0 -1
  94. data/lib/spree/testing_support/factories/payment_factory.rb +4 -0
  95. data/lib/spree/testing_support/factories/payment_method_factory.rb +8 -1
  96. data/lib/spree/testing_support/factories/user_factory.rb +2 -2
  97. data/solidus_core.gemspec +4 -3
  98. data/spec/helpers/base_helper_spec.rb +0 -40
  99. data/spec/lib/spree/core/controller_helpers/pricing_spec.rb +16 -0
  100. data/spec/lib/spree/core/importer/order_spec.rb +27 -18
  101. data/spec/lib/spree/core/price_migrator_spec.rb +3 -1
  102. data/spec/lib/spree/core/testing_support/factories/order_factory_spec.rb +16 -0
  103. data/spec/lib/spree/core/unreturned_item_charger_spec.rb +0 -2
  104. data/spec/lib/tasks/exchanges_spec.rb +4 -2
  105. data/spec/lib/tasks/migrations/create_vat_prices_spec.rb +5 -3
  106. data/spec/models/spree/adjustment_spec.rb +136 -0
  107. data/spec/models/spree/calculator/default_tax_spec.rb +13 -7
  108. data/spec/models/spree/calculator/flat_percent_item_total_spec.rb +3 -0
  109. data/spec/models/spree/calculator/flat_rate_spec.rb +3 -0
  110. data/spec/models/spree/calculator/flexi_rate_spec.rb +3 -0
  111. data/spec/models/spree/calculator/free_shipping_spec.rb +6 -0
  112. data/spec/models/spree/calculator/percent_on_line_item_spec.rb +9 -4
  113. data/spec/models/spree/calculator/percent_per_item_spec.rb +10 -0
  114. data/spec/models/spree/calculator/price_sack_spec.rb +3 -0
  115. data/spec/models/spree/calculator/refunds/default_refund_amount_spec.rb +3 -0
  116. data/spec/models/spree/calculator/shipping/flat_percent_item_total_spec.rb +3 -0
  117. data/spec/models/spree/calculator/shipping/flat_rate_spec.rb +3 -0
  118. data/spec/models/spree/calculator/shipping/flexi_rate_spec.rb +3 -0
  119. data/spec/models/spree/calculator/shipping/per_item_spec.rb +3 -0
  120. data/spec/models/spree/calculator/shipping/price_sack_spec.rb +4 -1
  121. data/spec/models/spree/calculator/tiered_flat_rate_spec.rb +3 -0
  122. data/spec/models/spree/calculator/tiered_percent_spec.rb +3 -0
  123. data/spec/models/spree/credit_card_spec.rb +27 -1
  124. data/spec/models/spree/line_item_spec.rb +58 -65
  125. data/spec/models/spree/order/checkout_spec.rb +2 -1
  126. data/spec/models/spree/order/payment_spec.rb +9 -10
  127. data/spec/models/spree/order/tax_spec.rb +22 -7
  128. data/spec/models/spree/order/updating_spec.rb +1 -3
  129. data/spec/models/spree/order_cancellations_spec.rb +6 -4
  130. data/spec/models/spree/order_contents_spec.rb +34 -50
  131. data/spec/models/spree/order_inventory_spec.rb +3 -5
  132. data/spec/models/spree/order_merger_spec.rb +20 -0
  133. data/spec/models/spree/order_spec.rb +28 -64
  134. data/spec/models/spree/order_update_attributes_spec.rb +1 -5
  135. data/spec/models/spree/order_updater_spec.rb +251 -0
  136. data/spec/models/spree/payment_method_spec.rb +178 -28
  137. data/spec/models/spree/payment_spec.rb +35 -19
  138. data/spec/models/spree/permission_sets/configuration_display.rb +0 -4
  139. data/spec/models/spree/permission_sets/configuration_management_spec.rb +0 -2
  140. data/spec/models/spree/permission_sets/product_display_spec.rb +0 -4
  141. data/spec/models/spree/permission_sets/product_management_spec.rb +0 -2
  142. data/spec/models/spree/permission_sets/user_management_spec.rb +9 -2
  143. data/spec/models/spree/price_spec.rb +16 -1
  144. data/spec/models/spree/product_spec.rb +0 -75
  145. data/spec/models/spree/promotion/actions/create_adjustment_spec.rb +20 -0
  146. data/spec/models/spree/promotion/actions/create_item_adjustments_spec.rb +39 -15
  147. data/spec/models/spree/promotion/actions/create_quantity_adjustments_spec.rb +203 -22
  148. data/spec/models/spree/promotion/actions/free_shipping_spec.rb +22 -3
  149. data/spec/models/spree/promotion/rules/taxon_spec.rb +26 -0
  150. data/spec/models/spree/promotion/rules/user_role_spec.rb +86 -0
  151. data/spec/models/spree/promotion_action_spec.rb +38 -0
  152. data/spec/models/spree/promotion_handler/coupon_spec.rb +36 -33
  153. data/spec/models/spree/promotion_handler/free_shipping_spec.rb +21 -22
  154. data/spec/models/spree/promotion_spec.rb +46 -6
  155. data/spec/models/spree/reimbursement_spec.rb +1 -1
  156. data/spec/models/spree/reimbursement_tax_calculator_spec.rb +2 -2
  157. data/spec/models/spree/shipment_spec.rb +68 -50
  158. data/spec/models/spree/shipping_method_spec.rb +41 -0
  159. data/spec/models/spree/shipping_rate_spec.rb +9 -3
  160. data/spec/models/spree/stock/estimator_spec.rb +4 -2
  161. data/spec/models/spree/store_credit_spec.rb +3 -3
  162. data/spec/models/spree/tax/item_adjuster_spec.rb +31 -21
  163. data/spec/models/spree/tax/order_adjuster_spec.rb +6 -10
  164. data/spec/models/spree/tax/taxation_integration_spec.rb +19 -0
  165. data/spec/models/spree/tax_rate_spec.rb +5 -26
  166. data/spec/models/spree/transfer_item_spec.rb +11 -0
  167. data/spec/models/spree/variant/pricing_options_spec.rb +7 -17
  168. data/spec/models/spree/variant_spec.rb +2 -4
  169. data/spec/models/spree/zone_spec.rb +60 -20
  170. data/spec/shared_examples/calculator_shared_examples.rb +8 -0
  171. metadata +19 -24
  172. data/app/models/spree/item_adjustments.rb +0 -89
  173. data/app/models/spree/option_type_prototype.rb +0 -6
  174. data/app/models/spree/property_prototype.rb +0 -6
  175. data/app/models/spree/prototype.rb +0 -14
  176. data/app/models/spree/prototype_taxon.rb +0 -6
  177. data/app/models/spree/tracker.rb +0 -8
  178. data/db/migrate/20150128032538_remove_environment_from_tracker.rb +0 -6
  179. data/lib/generators/spree/dummy/templates/initializers/custom_user.rb +0 -1
  180. data/lib/spree/core/delegate_belongs_to.rb +0 -94
  181. data/lib/spree/testing_support/factories/prototype_factory.rb +0 -8
  182. data/lib/spree/testing_support/factories/tracker_factory.rb +0 -6
  183. data/spec/lib/spree/core/delegate_belongs_to_spec.rb +0 -24
  184. data/spec/lib/spree/core/testing_support/factories/prototype_factory_spec.rb +0 -12
  185. data/spec/lib/spree/core/testing_support/factories/tracker_factory_spec.rb +0 -12
  186. data/spec/models/spree/item_adjustments_spec.rb +0 -306
  187. data/spec/models/spree/tracker_spec.rb +0 -21
@@ -1,11 +1,9 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Spree::Order, type: :model do
4
- let(:order) { stub_model(Spree::Order) }
4
+ let(:order) { create(:order) }
5
5
 
6
6
  context "#update!" do
7
- let(:line_items) { [mock_model(Spree::LineItem, amount: 5)] }
8
-
9
7
  context "when there are update hooks" do
10
8
  before { Spree::Order.register_update_hook :foo }
11
9
  after { Spree::Order.update_hooks.clear }
@@ -134,17 +134,19 @@ describe Spree::OrderCancellations do
134
134
  let(:line_item) { order.line_items.to_a.first }
135
135
  let(:inventory_unit_1) { line_item.inventory_units[0] }
136
136
  let(:inventory_unit_2) { line_item.inventory_units[1] }
137
+ let(:promotion) { create(:promotion, :with_line_item_adjustment) }
138
+ let(:promotion_action) { promotion.actions[0] }
137
139
 
138
140
  before do
139
141
  order.contents.add(line_item.variant)
140
142
 
141
143
  # make the total $1.67 so it divides unevenly
142
144
  line_item.adjustments.create!(
143
- source_type: 'Spree::TaxRate',
144
145
  order: order,
145
146
  amount: 0.01,
146
- label: 'some fake tax',
147
- finalized: true
147
+ label: 'some promo',
148
+ source: promotion_action,
149
+ finalized: true,
148
150
  )
149
151
  order.update!
150
152
  end
@@ -154,7 +156,7 @@ describe Spree::OrderCancellations do
154
156
  order.cancellations.short_ship([inventory_unit_2])
155
157
  expect(line_item.adjustments.map(&:amount)).to match_array(
156
158
  [
157
- 0.01, # tax adjustment
159
+ 0.01, # promo adjustment
158
160
  -0.84, # short ship 1
159
161
  -0.83, # short ship 2
160
162
  ]
@@ -2,12 +2,12 @@ require 'spec_helper'
2
2
 
3
3
  describe Spree::OrderContents, type: :model do
4
4
  let!(:store) { create :store }
5
- let(:order) { Spree::Order.create }
5
+ let(:order) { create(:order) }
6
6
  let(:variant) { create(:variant) }
7
7
  let!(:stock_location) { variant.stock_locations.first }
8
8
  let(:stock_location_2) { create(:stock_location) }
9
9
 
10
- subject { described_class.new(order) }
10
+ subject(:order_contents) { described_class.new(order) }
11
11
 
12
12
  context "#add" do
13
13
  context 'given quantity is not explicitly provided' do
@@ -96,6 +96,38 @@ describe Spree::OrderContents, type: :model do
96
96
  include_context "discount changes order total"
97
97
  end
98
98
  end
99
+
100
+ describe 'tax calculations' do
101
+ let!(:zone) { create(:global_zone) }
102
+ let!(:tax_rate) do
103
+ create(:tax_rate, zone: zone, tax_category: variant.tax_category)
104
+ end
105
+
106
+ context 'when the order has a taxable address' do
107
+ before do
108
+ expect(order.tax_address.country_id).to be_present
109
+ end
110
+
111
+ it 'creates a tax adjustment' do
112
+ order_contents.add(variant)
113
+ line_item = order.find_line_item_by_variant(variant)
114
+ expect(line_item.adjustments.tax.count).to eq(1)
115
+ end
116
+ end
117
+
118
+ context 'when the order does not have a taxable address' do
119
+ before do
120
+ order.update_attributes!(ship_address: nil, bill_address: nil)
121
+ expect(order.tax_address.country_id).to be_nil
122
+ end
123
+
124
+ it 'creates a tax adjustment' do
125
+ order_contents.add(variant)
126
+ line_item = order.find_line_item_by_variant(variant)
127
+ expect(line_item.adjustments.tax.count).to eq(0)
128
+ end
129
+ end
130
+ end
99
131
  end
100
132
 
101
133
  context "#remove" do
@@ -224,54 +256,6 @@ describe Spree::OrderContents, type: :model do
224
256
  }.to change { subject.order.total }
225
257
  end
226
258
 
227
- context "given an order with existing addresses" do
228
- let(:default_address) { create :address, state_code: "NY", zipcode: "17402" }
229
- let(:order_with_address ) { create :order, ship_address: default_address, bill_address: default_address }
230
-
231
- subject { described_class.new(order_with_address) }
232
-
233
- context "when an address in a potentially different tax zone is supplied " do
234
- let(:updated_address) { build :address, state_code: "AL", zipcode: "64092" }
235
-
236
- let(:params) do
237
- { ship_address_attributes: updated_address.value_attributes, bill_address_attributes: updated_address.value_attributes }
238
- end
239
-
240
- it "updates tax adjustments" do
241
- expect(subject.order).to receive(:create_tax_charge!)
242
- subject.update_cart params
243
- end
244
- end
245
-
246
- context "when an address in potentially the same tax zone is supplied" do
247
- let(:updated_address) { build :address, state_code: "NY", zipcode: "17402", firstname: 'Robert' }
248
-
249
- let(:params) do
250
- { ship_address_attributes: updated_address.value_attributes, bill_address_attributes: updated_address.value_attributes }
251
- end
252
-
253
- it "does not updates tax adjustments" do
254
- expect(subject.order).not_to receive(:create_tax_charge!)
255
- subject.update_cart params
256
- end
257
- end
258
- end
259
-
260
- context "given an order with no existing addresses" do
261
- context "when an address is supplied" do
262
- let(:updated_address) { build :address, state_code: "CA", zipcode: "14902" }
263
-
264
- let(:params) do
265
- { ship_address_attributes: updated_address.attributes, bill_address_attributes: updated_address.value_attributes }
266
- end
267
-
268
- it "does not updates tax adjustments" do
269
- expect(subject.order).not_to receive(:create_tax_charge!)
270
- subject.update_cart params
271
- end
272
- end
273
- end
274
-
275
259
  context "submits item quantity 0" do
276
260
  let(:params) do
277
261
  { line_items_attributes: {
@@ -201,12 +201,10 @@ describe Spree::OrderInventory, type: :model do
201
201
  end
202
202
 
203
203
  it 'should destroy self if not inventory units remain' do
204
- shipment.inventory_units[1...999].each(&:destroy)
205
- shipment.inventory_units.reload
204
+ allow(shipment.inventory_units).to receive_messages(count: 0)
205
+ expect(shipment).to receive(:destroy)
206
206
 
207
- expect {
208
- expect(subject.send(:remove_from_shipment, shipment, 1)).to eq(1)
209
- }.to change{ order.shipments.count }.from(1).to(0)
207
+ expect(subject.send(:remove_from_shipment, shipment, 1)).to eq(1)
210
208
  end
211
209
 
212
210
  context "inventory unit line item and variant points to different products" do
@@ -43,6 +43,26 @@ module Spree
43
43
  end
44
44
  end
45
45
 
46
+ context 'merging together two orders with multiple currencies line items' do
47
+ let(:order_2) { Spree::Order.create(currency: 'JPY') }
48
+ let(:variant_2) { create(:variant) }
49
+
50
+ before do
51
+ Spree::Price.create(variant: variant_2, amount: 10, currency: 'JPY')
52
+ order_1.contents.add(variant, 1)
53
+ order_2.contents.add(variant_2.reload, 1)
54
+ end
55
+
56
+ it 'rejects other order line items' do
57
+ subject.merge!(order_2, user)
58
+ expect(order_1.line_items.count).to eq(1)
59
+
60
+ line_item = order_1.line_items.first
61
+ expect(line_item.quantity).to eq(1)
62
+ expect(line_item.variant_id).to eq(variant.id)
63
+ end
64
+ end
65
+
46
66
  context "merging using extension-specific line_item_comparison_hooks" do
47
67
  before do
48
68
  Spree::Order.register_line_item_comparison_hook(:foos_match)
@@ -1,11 +1,5 @@
1
1
  require 'spec_helper'
2
2
 
3
- class FakeCalculator < Spree::Calculator
4
- def compute(_computable)
5
- 5
6
- end
7
- end
8
-
9
3
  describe Spree::Order, type: :model do
10
4
  let(:store) { build_stubbed(:store) }
11
5
  let(:user) { stub_model(Spree::LegacyUser, email: "spree@example.com") }
@@ -516,7 +510,8 @@ describe Spree::Order, type: :model do
516
510
  payment_method = Spree::PaymentMethod.create!({
517
511
  name: "Fake",
518
512
  active: true,
519
- display_on: "front_end"
513
+ available_to_users: true,
514
+ available_to_admin: false
520
515
  })
521
516
  expect(order.available_payment_methods).to include(payment_method)
522
517
  end
@@ -525,16 +520,18 @@ describe Spree::Order, type: :model do
525
520
  payment_method = Spree::PaymentMethod.create!({
526
521
  name: "Fake",
527
522
  active: true,
528
- display_on: "both"
523
+ available_to_users: true,
524
+ available_to_admin: true
529
525
  })
530
526
  expect(order.available_payment_methods).to include(payment_method)
531
527
  end
532
528
 
533
- it "does not include a payment method twice if display_on is blank" do
529
+ it "does not include a payment method twice" do
534
530
  payment_method = Spree::PaymentMethod.create!({
535
531
  name: "Fake",
536
532
  active: true,
537
- display_on: "both"
533
+ available_to_users: true,
534
+ available_to_admin: true
538
535
  })
539
536
  expect(order.available_payment_methods.count).to eq(1)
540
537
  expect(order.available_payment_methods).to include(payment_method)
@@ -543,8 +540,10 @@ describe Spree::Order, type: :model do
543
540
  context "with more than one payment method" do
544
541
  subject { order.available_payment_methods }
545
542
 
546
- let!(:first_method) { FactoryGirl.create(:payment_method, display_on: :both) }
547
- let!(:second_method) { FactoryGirl.create(:payment_method, display_on: :both) }
543
+ let!(:first_method) { FactoryGirl.create(:payment_method, available_to_users: true,
544
+ available_to_admin: true) }
545
+ let!(:second_method) { FactoryGirl.create(:payment_method, available_to_users: true,
546
+ available_to_admin: true) }
548
547
 
549
548
  before do
550
549
  second_method.move_to_top
@@ -575,6 +574,23 @@ describe Spree::Order, type: :model do
575
574
  [payment_method_with_store]
576
575
  )
577
576
  end
577
+
578
+ context 'and the store has an extra payment method unavailable to users' do
579
+ let!(:admin_only_payment_method) do create(:payment_method,
580
+ available_to_users: false,
581
+ available_to_admin: true)
582
+ end
583
+
584
+ before do
585
+ store_with_payment_methods.payment_methods << admin_only_payment_method
586
+ end
587
+
588
+ it 'returns only the payment methods available to users for that store' do
589
+ expect(order.available_payment_methods).to match_array(
590
+ [payment_method_with_store]
591
+ )
592
+ end
593
+ end
578
594
  end
579
595
 
580
596
  context 'when the store does not have payment methods' do
@@ -1488,56 +1504,4 @@ describe Spree::Order, type: :model do
1488
1504
  end
1489
1505
  end
1490
1506
  end
1491
-
1492
- describe "#validate_payments_attributes" do
1493
- let(:attributes) { [ActionController::Parameters.new(payment_method_id: payment_method.id)] }
1494
- subject do
1495
- order.validate_payments_attributes(attributes)
1496
- end
1497
-
1498
- context "with empty array" do
1499
- let(:attributes) { [] }
1500
- it "doesn't error" do
1501
- subject
1502
- end
1503
- end
1504
-
1505
- context "with no payment method specified" do
1506
- let(:attributes) { [ActionController::Parameters.new({})] }
1507
- it "doesn't error" do
1508
- subject
1509
- end
1510
- end
1511
-
1512
- context "with valid payment method" do
1513
- let(:payment_method) { create(:check_payment_method) }
1514
- it "doesn't error" do
1515
- subject
1516
- end
1517
- end
1518
-
1519
- context "with inactive payment method" do
1520
- let(:payment_method) { create(:check_payment_method, active: false) }
1521
-
1522
- it "raises RecordNotFound" do
1523
- expect { subject }.to raise_error(ActiveRecord::RecordNotFound)
1524
- end
1525
- end
1526
-
1527
- context "with unavailable payment method" do
1528
- let(:payment_method) { create(:check_payment_method, display_on: "back_end") }
1529
-
1530
- it "raises RecordNotFound" do
1531
- expect { subject }.to raise_error(ActiveRecord::RecordNotFound)
1532
- end
1533
- end
1534
-
1535
- context "with soft-deleted payment method" do
1536
- let(:payment_method) { create(:check_payment_method, deleted_at: Time.current) }
1537
-
1538
- it "raises RecordNotFound" do
1539
- expect { subject }.to raise_error(ActiveRecord::RecordNotFound)
1540
- end
1541
- end
1542
- end
1543
1507
  end
@@ -3,7 +3,6 @@ require 'spec_helper'
3
3
  module Spree
4
4
  RSpec.describe OrderUpdateAttributes do
5
5
  let(:order) { create(:order) }
6
- let(:payment_method) { create(:payment_method) }
7
6
  let(:request_env) { nil }
8
7
  let(:update) { described_class.new(order, attributes, request_env: request_env) }
9
8
 
@@ -26,10 +25,7 @@ module Spree
26
25
  let(:attributes) do
27
26
  {
28
27
  payments_attributes: [
29
- {
30
- payment_method_id: payment_method.id,
31
- source_attributes: attributes_for(:credit_card)
32
- }
28
+ { source_attributes: attributes_for(:credit_card) }
33
29
  ]
34
30
  }
35
31
  end
@@ -67,6 +67,257 @@ module Spree
67
67
  end
68
68
  end
69
69
 
70
+ describe '#recalculate_adjustments ' do
71
+ describe 'promotion recalculation' do
72
+ let(:order) { create(:order_with_line_items, line_items_count: 1, line_items_price: 10) }
73
+ let(:line_item) { order.line_items[0] }
74
+
75
+ context 'when the item quantity has changed' do
76
+ let(:promotion) { create(:promotion, promotion_actions: [promotion_action]) }
77
+ let(:promotion_action) { Spree::Promotion::Actions::CreateItemAdjustments.new(calculator: calculator) }
78
+ let(:calculator) { Spree::Calculator::FlatPercentItemTotal.new(preferred_flat_percent: 10) }
79
+
80
+ before do
81
+ promotion.activate(order: order)
82
+ order.update!
83
+ line_item.update!(quantity: 2)
84
+ end
85
+
86
+ it 'updates the promotion amount' do
87
+ expect {
88
+ order.update!
89
+ }.to change {
90
+ line_item.promo_total
91
+ }.from(-1).to(-2)
92
+ end
93
+ end
94
+
95
+ context 'promotion chooser customization' do
96
+ before do
97
+ class Spree::TestPromotionChooser
98
+ def initialize(_adjustments)
99
+ raise 'Custom promotion chooser'
100
+ end
101
+ end
102
+
103
+ Spree::Config.promotion_chooser_class = Spree::TestPromotionChooser
104
+ end
105
+
106
+ it 'uses the defined promotion chooser' do
107
+ expect { order.update! }.to raise_error('Custom promotion chooser')
108
+ end
109
+ end
110
+
111
+ context 'default promotion chooser (best promotion is always applied)' do
112
+ let(:calculator) { Calculator::FlatRate.new(preferred_amount: 10) }
113
+
114
+ let(:source) do
115
+ Promotion::Actions::CreateItemAdjustments.create!(
116
+ calculator: calculator,
117
+ promotion: promotion,
118
+ )
119
+ end
120
+ let(:promotion) { create(:promotion) }
121
+
122
+ def create_adjustment(label, amount)
123
+ create(
124
+ :adjustment,
125
+ order: order,
126
+ adjustable: line_item,
127
+ source: source,
128
+ amount: amount,
129
+ finalized: true,
130
+ label: label,
131
+ )
132
+ end
133
+
134
+ it 'should make all but the most valuable promotion adjustment ineligible, leaving non promotion adjustments alone' do
135
+ create_adjustment('Promotion A', -100)
136
+ create_adjustment('Promotion B', -200)
137
+ create_adjustment('Promotion C', -300)
138
+ create(:adjustment, order: order,
139
+ adjustable: line_item,
140
+ source: nil,
141
+ amount: -500,
142
+ finalized: true,
143
+ label: 'Some other credit')
144
+ line_item.adjustments.each { |a| a.update_column(:eligible, true) }
145
+
146
+ order.update!
147
+
148
+ expect(line_item.adjustments.promotion.eligible.count).to eq(1)
149
+ expect(line_item.adjustments.promotion.eligible.first.label).to eq('Promotion C')
150
+ end
151
+
152
+ it 'should choose the most recent promotion adjustment when amounts are equal' do
153
+ # Using Timecop is a regression test
154
+ Timecop.freeze do
155
+ create_adjustment('Promotion A', -200)
156
+ create_adjustment('Promotion B', -200)
157
+ end
158
+ line_item.adjustments.each { |a| a.update_column(:eligible, true) }
159
+
160
+ order.update!
161
+
162
+ expect(line_item.adjustments.promotion.eligible.count).to eq(1)
163
+ expect(line_item.adjustments.promotion.eligible.first.label).to eq('Promotion B')
164
+ end
165
+
166
+ it 'should choose the most recent promotion adjustment when amounts are equal' do
167
+ # Using Timecop is a regression test
168
+ Timecop.freeze do
169
+ create_adjustment('Promotion A', -200)
170
+ create_adjustment('Promotion B', -200)
171
+ end
172
+ line_item.adjustments.each { |a| a.update_column(:eligible, true) }
173
+
174
+ order.update!
175
+
176
+ expect(line_item.adjustments.promotion.eligible.count).to eq(1)
177
+ expect(line_item.adjustments.promotion.eligible.first.label).to eq('Promotion B')
178
+ end
179
+
180
+ context 'when previously ineligible promotions become available' do
181
+ let(:order_promo1) { create(:promotion, :with_order_adjustment, :with_item_total_rule, weighted_order_adjustment_amount: 5, item_total_threshold_amount: 10) }
182
+ let(:order_promo2) { create(:promotion, :with_order_adjustment, :with_item_total_rule, weighted_order_adjustment_amount: 10, item_total_threshold_amount: 20) }
183
+ let(:order_promos) { [order_promo1, order_promo2] }
184
+ let(:line_item_promo1) { create(:promotion, :with_line_item_adjustment, :with_item_total_rule, adjustment_rate: 2.5, item_total_threshold_amount: 10, apply_automatically: true) }
185
+ let(:line_item_promo2) { create(:promotion, :with_line_item_adjustment, :with_item_total_rule, adjustment_rate: 5, item_total_threshold_amount: 20, apply_automatically: true) }
186
+ let(:line_item_promos) { [line_item_promo1, line_item_promo2] }
187
+ let(:order) { create(:order_with_line_items, line_items_count: 1) }
188
+
189
+ # Apply promotions in different sequences. Results should be the same.
190
+ promo_sequences = [
191
+ [0, 1],
192
+ [1, 0],
193
+ ]
194
+
195
+ promo_sequences.each do |promo_sequence|
196
+ context "with promo sequence #{promo_sequence}" do
197
+ it 'should pick the best order-level promo according to current eligibility' do
198
+ # apply both promos to the order, even though only promo1 is eligible
199
+ order_promos[promo_sequence[0]].activate order: order
200
+ order_promos[promo_sequence[1]].activate order: order
201
+
202
+ order.update!
203
+ order.reload
204
+ expect(order.all_adjustments.count).to eq(2), 'Expected two adjustments'
205
+ expect(order.all_adjustments.eligible.count).to eq(1), 'Expected one elegible adjustment'
206
+ expect(order.all_adjustments.eligible.first.source.promotion).to eq(order_promo1), 'Expected promo1 to be used'
207
+
208
+ order.contents.add create(:variant, price: 10), 1
209
+ order.save
210
+
211
+ order.reload
212
+ expect(order.all_adjustments.count).to eq(2), 'Expected two adjustments'
213
+ expect(order.all_adjustments.eligible.count).to eq(1), 'Expected one elegible adjustment'
214
+ expect(order.all_adjustments.eligible.first.source.promotion).to eq(order_promo2), 'Expected promo2 to be used'
215
+ end
216
+
217
+ it 'should pick the best line-item-level promo according to current eligibility' do
218
+ # apply both promos to the order, even though only promo1 is eligible
219
+ line_item_promos[promo_sequence[0]].activate order: order
220
+ line_item_promos[promo_sequence[1]].activate order: order
221
+
222
+ order.reload
223
+ expect(order.all_adjustments.count).to eq(1), 'Expected one adjustment'
224
+ expect(order.all_adjustments.eligible.count).to eq(1), 'Expected one elegible adjustment'
225
+ # line_item_promo1 is the only one that has thus far met the order total threshold, it is the only promo which should be applied.
226
+ expect(order.all_adjustments.first.source.promotion).to eq(line_item_promo1), 'Expected line_item_promo1 to be used'
227
+
228
+ order.contents.add create(:variant, price: 10), 1
229
+ order.save
230
+
231
+ order.reload
232
+ expect(order.all_adjustments.count).to eq(4), 'Expected four adjustments'
233
+ expect(order.all_adjustments.eligible.count).to eq(2), 'Expected two elegible adjustments'
234
+ order.all_adjustments.eligible.each do |adjustment|
235
+ expect(adjustment.source.promotion).to eq(line_item_promo2), 'Expected line_item_promo2 to be used'
236
+ end
237
+ end
238
+ end
239
+ end
240
+ end
241
+
242
+ context 'multiple adjustments and the best one is not eligible' do
243
+ let!(:promo_a) { create_adjustment('Promotion A', -100) }
244
+ let!(:promo_c) { create_adjustment('Promotion C', -300) }
245
+
246
+ before do
247
+ promo_a.update_column(:eligible, true)
248
+ promo_c.update_column(:eligible, false)
249
+ end
250
+
251
+ # regression for https://github.com/spree/spree/issues/3274
252
+ it 'still makes the previous best eligible adjustment valid' do
253
+ order.update!
254
+ expect(line_item.adjustments.promotion.eligible.first.label).to eq('Promotion A')
255
+ end
256
+ end
257
+
258
+ it 'should only leave one adjustment even if 2 have the same amount' do
259
+ create_adjustment('Promotion A', -100)
260
+ create_adjustment('Promotion B', -200)
261
+ create_adjustment('Promotion C', -200)
262
+
263
+ order.update!
264
+
265
+ expect(line_item.adjustments.promotion.eligible.count).to eq(1)
266
+ expect(line_item.adjustments.promotion.eligible.first.amount.to_i).to eq(-200)
267
+ end
268
+ end
269
+ end
270
+
271
+ describe 'tax recalculation' do
272
+ let!(:ship_address) { create(:address) }
273
+ let!(:tax_zone) { create(:global_zone) } # will include the above address
274
+ let!(:tax_rate) { create(:tax_rate, zone: tax_zone, tax_category: tax_category) }
275
+
276
+ let(:order) do
277
+ create(
278
+ :order_with_line_items,
279
+ line_items_attributes: [{ price: 10, variant: variant }],
280
+ ship_address: ship_address,
281
+ )
282
+ end
283
+ let(:line_item) { order.line_items[0] }
284
+
285
+ let(:variant) { create(:variant, tax_category: tax_category) }
286
+ let(:tax_category) { create(:tax_category) }
287
+
288
+ context 'when the item quantity has changed' do
289
+ before do
290
+ line_item.update!(quantity: 2)
291
+ end
292
+
293
+ it 'updates the promotion amount' do
294
+ expect {
295
+ order.update!
296
+ }.to change {
297
+ line_item.additional_tax_total
298
+ }.from(1).to(2)
299
+ end
300
+ end
301
+
302
+ context 'with a custom tax_adjuster_class' do
303
+ let(:custom_adjuster_class) { double }
304
+ let(:custom_adjuster_instance) { double }
305
+
306
+ before do
307
+ order # generate this first so we can expect it
308
+ Spree::Config.tax_adjuster_class = custom_adjuster_class
309
+ end
310
+
311
+ it 'uses the configured class' do
312
+ expect(custom_adjuster_class).to receive(:new).with(order).at_least(:once).and_return(custom_adjuster_instance)
313
+ expect(custom_adjuster_instance).to receive(:adjust!).at_least(:once)
314
+
315
+ order.update!
316
+ end
317
+ end
318
+ end
319
+ end
320
+
70
321
  context "updating shipment state" do
71
322
  before do
72
323
  allow(order).to receive_messages backordered?: false