solidus_core 2.1.1 → 2.2.0.beta1

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 (145) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +0 -1
  3. data/app/assets/config/solidus_core_manifest.js +1 -0
  4. data/app/assets/javascripts/spree.js.erb +72 -0
  5. data/app/helpers/spree/store_helper.rb +5 -0
  6. data/app/jobs/spree/promotion_code_batch_job.rb +24 -0
  7. data/app/mailers/spree/promotion_code_batch_mailer.rb +13 -0
  8. data/app/models/concerns/spree/calculated_adjustments.rb +1 -1
  9. data/app/models/concerns/spree/ordered_property_value_list.rb +2 -2
  10. data/app/models/concerns/spree/user_address_book.rb +4 -4
  11. data/app/models/concerns/spree/user_methods.rb +7 -0
  12. data/app/models/concerns/spree/user_payment_source.rb +12 -5
  13. data/app/models/spree/address.rb +14 -3
  14. data/app/models/spree/adjustment.rb +13 -1
  15. data/app/models/spree/app_configuration.rb +0 -19
  16. data/app/models/spree/base.rb +2 -0
  17. data/app/models/spree/credit_card.rb +34 -43
  18. data/app/models/spree/gateway/bogus.rb +1 -1
  19. data/app/models/spree/gateway.rb +6 -4
  20. data/app/models/spree/inventory_unit.rb +3 -2
  21. data/app/models/spree/order/checkout.rb +187 -273
  22. data/app/models/spree/order.rb +137 -71
  23. data/app/models/spree/order_contents.rb +1 -1
  24. data/app/models/spree/order_inventory.rb +11 -11
  25. data/app/models/spree/order_promotion.rb +2 -0
  26. data/app/models/spree/order_update_attributes.rb +1 -8
  27. data/app/models/spree/order_updater.rb +67 -63
  28. data/app/models/spree/payment.rb +0 -1
  29. data/app/models/spree/payment_create.rb +27 -7
  30. data/app/models/spree/payment_method/store_credit.rb +3 -3
  31. data/app/models/spree/payment_method.rb +4 -1
  32. data/app/models/spree/payment_source.rb +45 -0
  33. data/app/models/spree/product/scopes.rb +24 -24
  34. data/app/models/spree/product.rb +4 -4
  35. data/app/models/spree/promotion.rb +2 -0
  36. data/app/models/spree/promotion_code/batch_builder.rb +63 -0
  37. data/app/models/spree/promotion_code.rb +1 -0
  38. data/app/models/spree/promotion_code_batch.rb +25 -0
  39. data/app/models/spree/promotion_handler/cart.rb +2 -2
  40. data/app/models/spree/promotion_handler/coupon.rb +1 -2
  41. data/app/models/spree/promotion_handler/free_shipping.rb +32 -21
  42. data/app/models/spree/promotion_handler/page.rb +1 -1
  43. data/app/models/spree/reimbursement.rb +1 -1
  44. data/app/models/spree/return_authorization.rb +0 -28
  45. data/app/models/spree/return_item.rb +1 -1
  46. data/app/models/spree/shipment.rb +4 -4
  47. data/app/models/spree/shipping_method.rb +2 -2
  48. data/app/models/spree/shipping_rate.rb +1 -1
  49. data/app/models/spree/stock/availability_validator.rb +16 -17
  50. data/app/models/spree/stock/coordinator.rb +3 -3
  51. data/app/models/spree/stock/package.rb +1 -1
  52. data/app/models/spree/stock/quantifier.rb +5 -4
  53. data/app/models/spree/stock_location.rb +2 -2
  54. data/app/models/spree/store.rb +2 -2
  55. data/app/models/spree/store_credit.rb +1 -1
  56. data/app/models/spree/tax/tax_helpers.rb +3 -3
  57. data/app/models/spree/tax_rate.rb +7 -1
  58. data/app/models/spree/taxonomy.rb +1 -1
  59. data/app/models/spree/variant/scopes.rb +5 -5
  60. data/app/models/spree/variant/vat_price_generator.rb +8 -5
  61. data/app/models/spree/variant.rb +1 -0
  62. data/app/models/spree/wallet/add_payment_sources_to_wallet.rb +19 -10
  63. data/app/models/spree/wallet/default_payment_builder.rb +6 -6
  64. data/app/models/spree/wallet.rb +71 -0
  65. data/app/models/spree/wallet_payment_source.rb +17 -0
  66. data/app/models/spree/zone.rb +1 -1
  67. data/app/views/spree/carton_mailer/shipped_email.text.erb +1 -1
  68. data/app/views/spree/promotion_code_batch_mailer/promotion_code_batch_errored.text.erb +2 -0
  69. data/app/views/spree/promotion_code_batch_mailer/promotion_code_batch_finished.text.erb +2 -0
  70. data/app/views/spree/reimbursement_mailer/reimbursement_email.html.erb +0 -7
  71. data/app/views/spree/reimbursement_mailer/reimbursement_email.text.erb +0 -5
  72. data/app/views/spree/shared/_error_messages.html.erb +1 -1
  73. data/app/views/spree/shipment_mailer/shipped_email.html.erb +1 -1
  74. data/config/initializers/assets.rb +1 -1
  75. data/config/initializers/friendly_id.rb +1 -1
  76. data/config/locales/en.yml +50 -12
  77. data/db/default/spree/store_credit.rb +2 -1
  78. data/db/migrate/20130826062534_add_depth_to_spree_taxons.rb +4 -6
  79. data/db/migrate/20160420044191_create_spree_wallet_payment_sources.rb +23 -0
  80. data/db/migrate/20160420181916_migrate_credit_cards_to_wallet_payment_sources.rb +26 -0
  81. data/db/migrate/20161017102621_create_spree_promotion_code_batch.rb +36 -0
  82. data/db/migrate/20161129035810_add_index_to_spree_payments_number.rb +5 -0
  83. data/db/migrate/20170223235001_remove_spree_store_credits_column.rb +5 -0
  84. data/lib/generators/spree/dummy/templates/rails/application.rb +1 -1
  85. data/lib/generators/spree/dummy/templates/rails/test.rb +1 -1
  86. data/lib/generators/spree/install/install_generator.rb +6 -5
  87. data/lib/spree/core/controller_helpers/payment_parameters.rb +54 -0
  88. data/lib/spree/core/engine.rb +6 -9
  89. data/lib/spree/core/version.rb +1 -1
  90. data/lib/spree/core.rb +0 -1
  91. data/lib/spree/money.rb +18 -0
  92. data/lib/spree/permission_sets/default_customer.rb +1 -1
  93. data/lib/spree/permitted_attributes.rb +1 -1
  94. data/lib/spree/testing_support/authorization_helpers.rb +1 -0
  95. data/lib/spree/testing_support/capybara_ext.rb +13 -0
  96. data/lib/spree/testing_support/factories/order_factory.rb +5 -1
  97. data/lib/spree/testing_support/factories/payment_factory.rb +1 -1
  98. data/lib/spree/testing_support/factories/shipment_factory.rb +0 -1
  99. data/solidus_core.gemspec +3 -3
  100. data/spec/jobs/promotion_code_batch_job_spec.rb +65 -0
  101. data/spec/lib/calculated_adjustments_spec.rb +105 -1
  102. data/spec/lib/spree/core/testing_support/factories/order_factory_spec.rb +4 -1
  103. data/spec/lib/spree/core/testing_support/factories/payment_factory_spec.rb +8 -0
  104. data/spec/lib/spree/money_spec.rb +32 -0
  105. data/spec/lib/spree/permission_sets/default_customer_spec.rb +20 -0
  106. data/spec/mailers/promotion_code_batch_mailer_spec.rb +45 -0
  107. data/spec/models/spree/credit_card_spec.rb +86 -86
  108. data/spec/models/spree/gateway_spec.rb +3 -1
  109. data/spec/models/spree/inventory_unit_spec.rb +12 -4
  110. data/spec/models/spree/order/checkout_spec.rb +11 -32
  111. data/spec/models/spree/order/tax_spec.rb +2 -2
  112. data/spec/models/spree/order_contents_spec.rb +24 -1
  113. data/spec/models/spree/order_inventory_spec.rb +130 -83
  114. data/spec/models/spree/order_spec.rb +15 -117
  115. data/spec/models/spree/order_update_attributes_spec.rb +1 -44
  116. data/spec/models/spree/order_updater_spec.rb +10 -13
  117. data/spec/models/spree/payment_create_spec.rb +5 -1
  118. data/spec/models/spree/payment_method_spec.rb +16 -0
  119. data/spec/models/spree/payment_spec.rb +14 -8
  120. data/spec/models/spree/promotion_code/batch_builder_spec.rb +61 -0
  121. data/spec/models/spree/promotion_code_batch_spec.rb +58 -0
  122. data/spec/models/spree/promotion_code_spec.rb +4 -0
  123. data/spec/models/spree/promotion_spec.rb +3 -6
  124. data/spec/models/spree/return_authorization_spec.rb +0 -59
  125. data/spec/models/spree/shipment_spec.rb +4 -4
  126. data/spec/models/spree/stock/availability_validator_spec.rb +64 -9
  127. data/spec/models/spree/tax/item_adjuster_spec.rb +1 -2
  128. data/spec/models/spree/unit_cancel_spec.rb +0 -85
  129. data/spec/models/spree/user_spec.rb +3 -1
  130. data/spec/models/spree/variant/vat_price_generator_spec.rb +8 -2
  131. data/spec/models/spree/variant_spec.rb +16 -4
  132. data/spec/models/spree/wallet_payment_source_spec.rb +46 -0
  133. data/spec/models/spree/wallet_spec.rb +128 -0
  134. data/spec/support/concerns/payment_source.rb +64 -0
  135. metadata +51 -25
  136. data/app/assets/javascripts/spree.js.coffee.erb +0 -64
  137. data/app/models/spree/promotion_builder.rb +0 -55
  138. data/app/models/spree/promotion_code/code_builder.rb +0 -62
  139. data/config/initializers/premailer_assets.rb +0 -1
  140. data/lib/spree/core/unreturned_item_charger.rb +0 -106
  141. data/lib/tasks/exchanges.rake +0 -47
  142. data/spec/lib/spree/core/unreturned_item_charger_spec.rb +0 -126
  143. data/spec/lib/tasks/exchanges_spec.rb +0 -220
  144. data/spec/models/spree/promotion_builder_spec.rb +0 -120
  145. data/spec/models/spree/promotion_code/code_builder_spec.rb +0 -77
@@ -1 +0,0 @@
1
- Rails.application.config.assets.precompile += %w( ink.css )
@@ -1,106 +0,0 @@
1
- module Spree
2
- class UnreturnedItemCharger
3
- class ChargeFailure < StandardError
4
- attr_accessor :new_order
5
- def initialize(message, new_order)
6
- @new_order = new_order
7
- super(message)
8
- end
9
- end
10
-
11
- class_attribute :failure_handler
12
-
13
- attr_reader :original_order, :new_order
14
-
15
- def initialize(shipment, return_items)
16
- @shipment = shipment
17
- @original_order = @shipment.order
18
- @return_items = return_items
19
- end
20
-
21
- def charge_for_items
22
- self.new_order = Spree::Order.create!(exchange_order_attributes)
23
-
24
- new_order.associate_user!(@original_order.user) if @original_order.user
25
-
26
- add_exchange_variants_to_order
27
- set_shipment_for_new_order
28
-
29
- new_order.update!
30
- set_order_payment
31
-
32
- # There are several checks in the order state machine to skip
33
- # certain transitions when an order is an unreturned exchange
34
- if !new_order.unreturned_exchange?
35
- raise ChargeFailure.new('order is not an unreturned exchange', new_order)
36
- end
37
-
38
- # Transitions will call update_totals on the order
39
- until new_order.can_complete?
40
- new_order.next!
41
- end
42
-
43
- new_order.contents.approve(name: self.class.name)
44
- new_order.complete!
45
- Spree::OrderCapturing.new(new_order).capture_payments if Spree::Config[:auto_capture_exchanges] && !Spree::Config[:auto_capture]
46
-
47
- @return_items.each(&:expired!)
48
- create_new_rma if Spree::Config[:create_rma_for_unreturned_exchange]
49
-
50
- if !new_order.completed?
51
- raise ChargeFailure.new('order not complete', new_order)
52
- elsif !new_order.valid?
53
- raise ChargeFailure.new('order not valid', new_order)
54
- end
55
- end
56
-
57
- private
58
-
59
- attr_writer :new_order
60
-
61
- def add_exchange_variants_to_order
62
- @return_items.group_by(&:exchange_variant).map do |variant, variant_return_items|
63
- variant_inventory_units = variant_return_items.map(&:exchange_inventory_unit)
64
- line_item = Spree::LineItem.create!(variant: variant, quantity: variant_return_items.count, order: new_order)
65
- variant_inventory_units.each { |i| i.update_attributes!(line_item_id: line_item.id, order_id: new_order.id) }
66
- end
67
- end
68
-
69
- def set_shipment_for_new_order
70
- @shipment.update_attributes!(order_id: new_order.id)
71
- new_order.shipments.reset
72
- end
73
-
74
- def set_order_payment
75
- unless new_order.payments.present?
76
- card_to_reuse = @original_order.valid_credit_cards.first
77
- card_to_reuse = @original_order.user.credit_cards.default.first if !card_to_reuse && @original_order.user
78
- new_order.payments.create!(
79
- payment_method_id: card_to_reuse.try(:payment_method_id),
80
- source: card_to_reuse,
81
- amount: new_order.total
82
- )
83
- end
84
- end
85
-
86
- def create_new_rma
87
- @return_items.group_by(&:return_authorization).each do |rma, return_items|
88
- new_return_items = return_items.map { |ri| Spree::ReturnItem.create!(inventory_unit: ri.inventory_unit) }
89
- Spree::ReturnAuthorization.create!(order: rma.order,
90
- reason: rma.reason,
91
- stock_location: rma.stock_location,
92
- return_items: new_return_items)
93
- end
94
- end
95
-
96
- def exchange_order_attributes
97
- {
98
- bill_address: @original_order.bill_address,
99
- ship_address: @original_order.ship_address,
100
- email: @original_order.email,
101
- store_id: @original_order.store_id,
102
- frontend_viewable: false
103
- }
104
- end
105
- end
106
- end
@@ -1,47 +0,0 @@
1
- namespace :exchanges do
2
- desc 'Takes unreturned exchanged items and creates a new order to charge
3
- the customer for not returning them'
4
- task charge_unreturned_items: :environment do
5
- unreturned_return_items = Spree::ReturnItem.expecting_return.exchange_processed.joins(:exchange_inventory_unit).where([
6
- "spree_inventory_units.created_at < :days_ago AND spree_inventory_units.state = :iu_state",
7
- days_ago: Spree::Config[:expedited_exchanges_days_window].days.ago, iu_state: "shipped"
8
- ]).preload(:exchange_inventory_unit).to_a
9
-
10
- # Determine that a return item has already been deemed unreturned and therefore charged
11
- # by the fact that its exchange inventory unit has popped off to a different order
12
- unreturned_return_items.select! { |ri| ri.inventory_unit.order_id == ri.exchange_inventory_unit.order_id }
13
-
14
- failures = []
15
-
16
- unreturned_return_items.group_by(&:exchange_shipment).each do |shipment, return_items|
17
- item_charger = Spree::UnreturnedItemCharger.new(shipment, return_items)
18
-
19
- begin
20
- item_charger.charge_for_items
21
- rescue Spree::UnreturnedItemCharger::ChargeFailure => e
22
- failure = { message: e.message }
23
- rescue => e
24
- failure = { message: "#{e.class}: #{e.message}" }
25
- end
26
-
27
- next unless failure
28
- failure[:new_order] = item_charger.new_order.number if item_charger.new_order
29
- failures << failure.merge({
30
- order: item_charger.original_order.number,
31
- shipment: shipment.number,
32
- return_items: return_items.map(&:id),
33
- order_errors: item_charger.original_order.errors.full_messages
34
- })
35
- end
36
-
37
- if failures.any?
38
- if Spree::UnreturnedItemCharger.failure_handler
39
- Spree::UnreturnedItemCharger.failure_handler.call(failures)
40
- else
41
- raise Spree::ChargeUnreturnedItemsFailures.new(failures.to_json)
42
- end
43
- end
44
- end
45
- end
46
-
47
- class Spree::ChargeUnreturnedItemsFailures < StandardError; end
@@ -1,126 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Spree::UnreturnedItemCharger do
4
- let(:ship_address) { create(:address) }
5
- let(:shipped_order) { create(:shipped_order, ship_address: ship_address, line_items_count: 1, with_cartons: false) }
6
- let(:original_shipment) { shipped_order.shipments.first }
7
- let(:original_stock_location) { original_shipment.stock_location }
8
- let(:original_inventory_unit) { shipped_order.inventory_units.first }
9
- let(:original_variant) { original_inventory_unit.variant }
10
- let(:shipping_method) { create(:shipping_method, tax_category: original_variant.tax_category) }
11
-
12
- let(:exchange_shipment) do
13
- create(:shipment,
14
- order: shipped_order,
15
- state: 'shipped',
16
- stock_location: original_stock_location,
17
- created_at: 5.days.ago,
18
- shipping_method: shipping_method)
19
- end
20
- let(:exchange_inventory_unit) { exchange_shipment.inventory_units.first }
21
- let(:return_item) do
22
- create(:exchange_return_item,
23
- inventory_unit: original_inventory_unit,
24
- exchange_inventory_unit: exchange_inventory_unit)
25
- end
26
-
27
- let!(:unreturned_item_charger) { Spree::UnreturnedItemCharger.new(exchange_shipment, [return_item]) }
28
-
29
- before do
30
- exchange_shipment.finalize!
31
- exchange_inventory_unit.ship!
32
- end
33
-
34
- shared_examples 'charge_for_items success' do
35
- let(:new_order) do
36
- subject
37
- exchange_inventory_unit.shipment.order.reload
38
- end
39
-
40
- it "reuses the same inventory unit" do
41
- expect { subject }.not_to change { Spree::InventoryUnit.count }
42
- end
43
-
44
- it "reuses the same shipment" do
45
- expect { subject }.not_to change { Spree::Shipment.count }
46
- expect(new_order.shipments.count).to eq 1
47
- end
48
-
49
- context 'in tax zone' do
50
- let!(:tax_zone) { create(:zone, countries: [ship_address.country]) }
51
- let!(:tax_rate) { create(:tax_rate, zone: tax_zone, tax_category: original_variant.tax_category) }
52
-
53
- it "applies tax" do
54
- exchange_order = exchange_shipment.order
55
- exchange_order.update!
56
- subject
57
- expect(new_order.additional_tax_total).to be > 0
58
- expect(new_order.line_items[0].additional_tax_total).to be > 0
59
- expect(new_order.shipments[0].additional_tax_total).to be > 0
60
- end
61
- end
62
-
63
- it "creates a new completed order" do
64
- expect { subject }.to change { Spree::Order.count }.by(1)
65
- expect(new_order).to_not eq(shipped_order)
66
- expect(new_order).to be_completed
67
- end
68
-
69
- it "authorizes payment" do
70
- expect { subject }.to change { Spree::Payment.count }.by(1)
71
- expect(new_order.payments.count).to eq 1
72
- expect(new_order.payments.first).to be_pending
73
- expect(new_order.payments.first.response_code).to be_present
74
- end
75
-
76
- it "delivers confirmation email" do
77
- expect { subject }.to change { ActionMailer::Base.deliveries.count }.by(1)
78
- end
79
-
80
- context 'with auto_capture_exchanges' do
81
- before { Spree::Config[:auto_capture_exchanges] = true }
82
-
83
- it "captures payment" do
84
- expect { subject }.to change { Spree::Payment.count }.by(1)
85
- expect(new_order.payments.count).to eq 1
86
- expect(new_order.payments.first).to be_completed
87
- expect(new_order.payment_state).to eq "paid"
88
- end
89
- end
90
- end
91
-
92
- describe "#charge_for_items" do
93
- before do
94
- original_variant.update_attributes!(track_inventory: true)
95
- original_variant.stock_items.update_all(backorderable: false)
96
- end
97
-
98
- subject { unreturned_item_charger.charge_for_items }
99
-
100
- context "new order is not an unreturned exchange" do
101
- before do
102
- allow_any_instance_of(Spree::Shipment).to receive(:update_attributes!)
103
- end
104
-
105
- it "raises an error" do
106
- expect { subject }.to raise_error(Spree::UnreturnedItemCharger::ChargeFailure, 'order is not an unreturned exchange')
107
- end
108
- end
109
-
110
- context "item is in stock" do
111
- before do
112
- original_variant.stock_items.map { |si| si.set_count_on_hand(10) }
113
- end
114
-
115
- include_examples 'charge_for_items success'
116
- end
117
-
118
- context "item is now out of stock" do
119
- before do
120
- original_variant.stock_items.map { |si| si.set_count_on_hand(0) }
121
- end
122
-
123
- include_examples 'charge_for_items success'
124
- end
125
- end
126
- end
@@ -1,220 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe "exchanges:charge_unreturned_items" do
4
- include_context(
5
- 'rake',
6
- task_name: 'exchanges:charge_unreturned_items',
7
- task_path: Spree::Core::Engine.root.join('lib/tasks/exchanges.rake'),
8
- )
9
-
10
- subject { task }
11
-
12
- describe '#prerequisites' do
13
- it { expect(subject.prerequisites).to include("environment") }
14
- end
15
-
16
- before do
17
- Spree::Config[:expedited_exchanges] = true
18
- Spree::StockItem.update_all(count_on_hand: 10)
19
- end
20
-
21
- context "there are no unreturned items" do
22
- it { expect { subject.invoke }.not_to change { Spree::Order.count } }
23
- end
24
-
25
- context "there are return items in an intermediate return status" do
26
- let!(:order) { create(:shipped_order, line_items_count: 2) }
27
- let(:return_item_1) { build(:exchange_return_item, inventory_unit: order.inventory_units.first) }
28
- let(:return_item_2) { build(:exchange_return_item, inventory_unit: order.inventory_units.last) }
29
- let!(:rma) { create(:return_authorization, order: order, return_items: [return_item_1, return_item_2]) }
30
- let(:zone) { create(:zone, countries: [order.tax_address.country])}
31
- let!(:tax_rate) { create(:tax_rate, zone: zone, tax_category: return_item_2.exchange_variant.tax_category) }
32
- before do
33
- rma.save!
34
- Spree::Shipment.last.ship!
35
- return_item_1.lost!
36
- return_item_2.give!
37
- Timecop.travel((Spree::Config[:expedited_exchanges_days_window] + 1).days)
38
- end
39
- after { Timecop.return }
40
- it { expect { subject.invoke }.not_to change { Spree::Order.count } }
41
- end
42
-
43
- context "there are unreturned items" do
44
- let!(:order) { create(:shipped_order, line_items_count: 2) }
45
- let(:return_item_1) { build(:exchange_return_item, inventory_unit: order.inventory_units.first) }
46
- let(:return_item_2) { build(:exchange_return_item, inventory_unit: order.inventory_units.last) }
47
- let!(:rma) { create(:return_authorization, order: order, return_items: [return_item_1, return_item_2]) }
48
- let(:zone) { create(:zone, countries: [order.tax_address.country])}
49
- let!(:tax_rate) { create(:tax_rate, zone: zone, tax_category: return_item_2.exchange_variant.tax_category) }
50
-
51
- before do
52
- rma.save!
53
- Spree::Shipment.last.ship!
54
- return_item_1.receive!
55
- Timecop.travel travel_time
56
- end
57
-
58
- after { Timecop.return }
59
-
60
- context "fewer than the config allowed days have passed" do
61
- let(:travel_time) { (Spree::Config[:expedited_exchanges_days_window] - 1).days }
62
-
63
- it "does not create a new order" do
64
- expect { subject.invoke }.not_to change { Spree::Order.count }
65
- end
66
- end
67
-
68
- context "more than the config allowed days have passed" do
69
- let(:travel_time) { (Spree::Config[:expedited_exchanges_days_window] + 1).days }
70
-
71
- it "creates a new completed order" do
72
- expect { subject.invoke }.to change { Spree::Order.count }
73
- expect(Spree::Order.last).to be_completed
74
- end
75
-
76
- it "sets frontend_viewable to false" do
77
- subject.invoke
78
- expect(Spree::Order.last).not_to be_frontend_viewable
79
- end
80
-
81
- it "moves the shipment for the unreturned items to the new order" do
82
- subject.invoke
83
- new_order = Spree::Order.last
84
- expect(new_order.shipments.count).to eq 1
85
- expect(return_item_2.reload.exchange_shipment.order).to eq Spree::Order.last
86
- end
87
-
88
- it "creates line items on the order for the unreturned items" do
89
- subject.invoke
90
- expect(Spree::Order.last.line_items.map(&:variant)).to eq [return_item_2.exchange_variant]
91
- end
92
-
93
- it "associates the exchanges inventory units with the new line items" do
94
- subject.invoke
95
- expect(return_item_2.reload.exchange_inventory_unit.try(:line_item).try(:order)).to eq Spree::Order.last
96
- end
97
-
98
- it "uses the credit card from the previous order" do
99
- subject.invoke
100
- new_order = Spree::Order.last
101
- expect(new_order.credit_cards).to be_present
102
- expect(new_order.credit_cards.first).to eq order.valid_credit_cards.first
103
- end
104
-
105
- context "payments" do
106
- it "authorizes the order for the full amount of the unreturned items including taxes" do
107
- expect { subject.invoke }.to change { Spree::Payment.count }.by(1)
108
- new_order = Spree::Order.last
109
- expected_amount = return_item_2.reload.exchange_variant.price + new_order.additional_tax_total + new_order.included_tax_total + new_order.shipment_total
110
- expect(new_order.total).to eq expected_amount
111
- payment = new_order.payments.first
112
- expect(payment.amount).to eq expected_amount
113
- expect(new_order.item_total).to eq return_item_2.reload.exchange_variant.price
114
- end
115
-
116
- context "auto_capture_exchanges is true" do
117
- before do
118
- Spree::Config[:auto_capture_exchanges] = true
119
- end
120
-
121
- it 'creates a pending payment' do
122
- expect { subject.invoke }.to change { Spree::Payment.count }.by(1)
123
- payment = Spree::Payment.last
124
- expect(payment).to be_completed
125
- end
126
- end
127
-
128
- context "auto_capture_exchanges is false" do
129
- before do
130
- Spree::Config[:auto_capture_exchanges] = false
131
- end
132
-
133
- it 'captures payment' do
134
- expect { subject.invoke }.to change { Spree::Payment.count }.by(1)
135
- payment = Spree::Payment.last
136
- expect(payment).to be_pending
137
- end
138
- end
139
- end
140
-
141
- it "does not attempt to create a new order for the item more than once" do
142
- subject.invoke
143
- subject.reenable
144
- expect { subject.invoke }.not_to change { Spree::Order.count }
145
- end
146
-
147
- it "associates the store of the original order with the exchange order" do
148
- store = order.store
149
- expect(Spree::Order).to receive(:create!).once.with(hash_including({ store_id: store.id })).and_call_original
150
- subject.invoke
151
- end
152
-
153
- it 'approves the order' do
154
- subject.invoke
155
- new_order = Spree::Order.last
156
- expect(new_order).to be_approved
157
- expect(new_order.is_risky?).to eq false
158
- expect(new_order.approver_name).to eq "Spree::UnreturnedItemCharger"
159
- expect(new_order.approver).to be nil
160
- end
161
-
162
- context "there is no card from the previous order" do
163
- let!(:credit_card) { create(:credit_card, user: order.user, default: true, gateway_customer_profile_id: "BGS-123") }
164
- before { allow_any_instance_of(Spree::Order).to receive(:valid_credit_cards) { [] } }
165
-
166
- it "attempts to use the user's default card" do
167
- expect { subject.invoke }.to change { Spree::Payment.count }.by(1)
168
- new_order = Spree::Order.last
169
- expect(new_order.credit_cards).to be_present
170
- expect(new_order.credit_cards.first).to eq credit_card
171
- end
172
- end
173
-
174
- context "it is unable to authorize the credit card" do
175
- before { allow_any_instance_of(Spree::Payment).to receive(:authorize!).and_raise(RuntimeError) }
176
-
177
- it "raises an error with the order" do
178
- expect { subject.invoke }.to raise_error(Spree::ChargeUnreturnedItemsFailures)
179
- end
180
- end
181
-
182
- context "the exchange inventory unit is not shipped" do
183
- before { return_item_2.reload.exchange_inventory_unit.update_columns(state: "on hand") }
184
- it "does not create a new order" do
185
- expect { subject.invoke }.not_to change { Spree::Order.count }
186
- end
187
- end
188
-
189
- context "the exchange inventory unit has been returned" do
190
- before { return_item_2.reload.exchange_inventory_unit.update_columns(state: "returned") }
191
- it "does not create a new order" do
192
- expect { subject.invoke }.not_to change { Spree::Order.count }
193
- end
194
- end
195
-
196
- context 'rma for unreturned exchanges' do
197
- context 'config to not create' do
198
- before { Spree::Config[:create_rma_for_unreturned_exchange] = false }
199
-
200
- it 'does not create rma' do
201
- expect { subject.invoke }.not_to change { Spree::ReturnAuthorization.count }
202
- end
203
- end
204
-
205
- context 'config to create' do
206
- before do
207
- Spree::Config[:create_rma_for_unreturned_exchange] = true
208
- end
209
-
210
- it 'creates with return items' do
211
- expect { subject.invoke }.to change { Spree::ReturnAuthorization.count }
212
- rma = Spree::ReturnAuthorization.last
213
-
214
- expect(rma.return_items.all?(&:awaiting?)).to be true
215
- end
216
- end
217
- end
218
- end
219
- end
220
- end
@@ -1,120 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Spree::PromotionBuilder do
4
- let(:promotion) { build(:promotion) }
5
- let(:base_code) { 'abc' }
6
- let(:number_of_codes) { 1 }
7
- let(:promotion_attrs) { { name: 'some promo' } }
8
- let(:builder) {
9
- Spree::PromotionBuilder.new(
10
- {
11
- base_code: base_code,
12
- number_of_codes: number_of_codes
13
- },
14
- promotion_attrs
15
- )
16
- }
17
-
18
- describe '#initialize' do
19
- subject { builder }
20
- it 'has the right base code' do
21
- expect(subject.base_code).to eq 'abc'
22
- end
23
-
24
- it 'has the right base code' do
25
- expect(subject.number_of_codes).to eq 1
26
- end
27
- end
28
-
29
- describe '#valid?' do
30
- subject { builder.valid? }
31
-
32
- it 'is true' do
33
- expect(subject).to be
34
- end
35
-
36
- context 'promotion is not valid' do
37
- let(:promotion_attrs) { { name: nil } }
38
-
39
- it 'is true' do
40
- expect(subject).to_not be
41
- end
42
-
43
- it 'has errors on the promotion' do
44
- subject
45
- expect(builder.errors).to_not be_empty
46
- end
47
- end
48
-
49
- context 'number of codes is invalid' do
50
- let(:number_of_codes) { -1 }
51
-
52
- it 'is false ' do
53
- expect(subject).to_not be
54
- end
55
-
56
- it 'validates numericality' do
57
- subject
58
- expect(builder.errors.full_messages).to eq ["Number of codes must be greater than 0"]
59
- end
60
- end
61
- end
62
-
63
- describe '#number_of_codes=' do
64
- it 'coerces a string' do
65
- builder.number_of_codes = '3'
66
- expect(builder.number_of_codes).to eq 3
67
- end
68
-
69
- it 'is nil for empty string' do
70
- builder.number_of_codes = ''
71
- expect(builder.number_of_codes).to be_nil
72
- end
73
- end
74
-
75
- describe "#perform" do
76
- subject { builder.perform }
77
-
78
- context 'when the builder is invalid' do
79
- let(:number_of_codes) { 'sups' }
80
-
81
- it 'returns false' do
82
- expect(subject).to_not be
83
- end
84
- end
85
-
86
- context "when the builder is valid" do
87
- context "when the builder cant build promotion codes" do
88
- let(:number_of_codes) { nil }
89
-
90
- it "doesn't create any new codes" do
91
- subject
92
- expect(builder.promotion.codes).to be_empty
93
- end
94
- end
95
-
96
- context "when the builder can build promotion codes" do
97
- let(:number_of_codes) { 1 }
98
-
99
- it "creates the correct number of codes" do
100
- subject
101
- expect(builder.promotion.codes.length).to eq number_of_codes
102
- end
103
-
104
- it "creates the promotion with the correct code" do
105
- subject
106
- expect(builder.promotion.codes.first.value).to eq base_code
107
- end
108
- end
109
-
110
- it "saves the promotion" do
111
- subject
112
- expect(builder.promotion).to be_persisted
113
- end
114
-
115
- it "returns true on success" do
116
- expect(subject).to be true
117
- end
118
- end
119
- end
120
- end
@@ -1,77 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Spree::PromotionCode::CodeBuilder do
4
- let(:promotion) { build_stubbed :promotion }
5
- let(:base_code) { "abc" }
6
- let(:builder) do
7
- described_class.new promotion, base_code, num_codes
8
- end
9
-
10
- describe "#build_promotion_codes" do
11
- subject { builder.build_promotion_codes }
12
-
13
- context "with one code" do
14
- let(:num_codes) { 1 }
15
-
16
- it "builds a single promotion code" do
17
- subject
18
- expect(builder.promotion.codes.size).to eq(num_codes)
19
- end
20
-
21
- it "creates the promotion code with the correct value" do
22
- subject
23
- expect(builder.promotion.codes.first.value).to eq base_code
24
- end
25
- end
26
-
27
- context "with more than one code" do
28
- let(:num_codes) { 2 }
29
-
30
- it "builds the correct number of codes" do
31
- subject
32
- expect(builder.promotion.codes.size).to eq(num_codes)
33
- end
34
-
35
- it "builds codes with distinct values" do
36
- subject
37
- expect(builder.promotion.codes.map(&:value).uniq.size).to eq(num_codes)
38
- end
39
-
40
- it "builds codes with the same base prefix" do
41
- subject
42
- values = builder.promotion.codes.map(&:value)
43
- expect(values.all? { |val| val.starts_with?("#{base_code}_") }).to be true
44
- end
45
-
46
- context 'when every possible code must be used' do
47
- before do
48
- @old_length = described_class.random_code_length
49
- described_class.random_code_length = 1
50
- end
51
- after { described_class.random_code_length = @old_length }
52
-
53
- let(:num_codes) { 26 }
54
-
55
- it "resolves the collision" do
56
- subject
57
- expect(builder.promotion.codes.map(&:value).uniq.size).to eq(num_codes)
58
- end
59
- end
60
-
61
- context "when collisions occur" do
62
- before do
63
- @old_length = described_class.random_code_length
64
- described_class.random_code_length = 1
65
- end
66
- after { described_class.random_code_length = @old_length }
67
-
68
- let(:num_codes) { 25 } # every possible code except 1
69
-
70
- it "resolves the collisions and returns the correct number of codes" do
71
- subject
72
- expect(builder.promotion.codes.map(&:value).uniq.size).to eq(num_codes)
73
- end
74
- end
75
- end
76
- end
77
- end