solidus_core 2.1.1 → 2.2.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 (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
@@ -2,11 +2,11 @@ require 'spree/core/validators/email'
2
2
  require 'spree/order/checkout'
3
3
 
4
4
  module Spree
5
- # The customers cart until completed, then acts as permenent record of the transaction.
5
+ # The customers cart until completed, then acts as permanent record of the transaction.
6
6
  #
7
7
  # `Spree::Order` is the heart of the Solidus system, as it acts as the customer's
8
8
  # cart as they shop. Once an order is complete, it serves as the
9
- # permenent record of their purchase. It has many responsibilities:
9
+ # permanent record of their purchase. It has many responsibilities:
10
10
  #
11
11
  # * Records and validates attributes like `total` and relationships like
12
12
  # `Spree::LineItem` as an ActiveRecord model.
@@ -43,17 +43,20 @@ module Spree
43
43
  go_to_state :confirm
44
44
  end
45
45
 
46
- self.whitelisted_ransackable_associations = %w[shipments user promotions bill_address ship_address line_items]
46
+ self.whitelisted_ransackable_associations = %w[shipments user order_promotions promotions bill_address ship_address line_items]
47
47
  self.whitelisted_ransackable_attributes = %w[completed_at created_at email number state payment_state shipment_state total store_id]
48
48
 
49
49
  attr_reader :coupon_code
50
- attr_accessor :temporary_address, :temporary_credit_card
50
+ attr_accessor :temporary_address
51
51
 
52
- belongs_to :user, class_name: Spree::UserClassHandle.new
53
- belongs_to :created_by, class_name: Spree::UserClassHandle.new
54
- belongs_to :approver, class_name: Spree::UserClassHandle.new
55
- belongs_to :canceler, class_name: Spree::UserClassHandle.new
52
+ attr_accessor :temporary_payment_source
53
+ alias_method :temporary_credit_card, :temporary_payment_source
54
+ alias_method :temporary_credit_card=, :temporary_payment_source=
55
+ deprecate temporary_credit_card: :temporary_payment_source, deprecator: Spree::Deprecation
56
+ deprecate :temporary_credit_card= => :temporary_payment_source=, deprecator: Spree::Deprecation
56
57
 
58
+ # Customer info
59
+ belongs_to :user, class_name: Spree::UserClassHandle.new
57
60
  belongs_to :bill_address, foreign_key: :bill_address_id, class_name: 'Spree::Address'
58
61
  alias_attribute :billing_address, :bill_address
59
62
 
@@ -62,36 +65,48 @@ module Spree
62
65
  alias_attribute :ship_total, :shipment_total
63
66
 
64
67
  belongs_to :store, class_name: 'Spree::Store'
65
- has_many :state_changes, as: :stateful
68
+
69
+ # Items
66
70
  has_many :line_items, -> { order(:created_at, :id) }, dependent: :destroy, inverse_of: :order
67
- has_many :payments, dependent: :destroy, inverse_of: :order
68
- has_many :return_authorizations, dependent: :destroy, inverse_of: :order
69
- has_many :reimbursements, inverse_of: :order
71
+ has_many :variants, through: :line_items
72
+ has_many :products, through: :variants
73
+
74
+ # Shipping
75
+ has_many :inventory_units, inverse_of: :order
76
+ has_many :cartons, -> { distinct }, through: :inventory_units
77
+ has_many :shipments, dependent: :destroy, inverse_of: :order do
78
+ def states
79
+ pluck(:state).uniq
80
+ end
81
+ end
82
+ has_many :order_stock_locations, class_name: "Spree::OrderStockLocation"
83
+ has_many :stock_locations, through: :order_stock_locations
84
+
85
+ # Adjustments and promotions
70
86
  has_many :adjustments, -> { order(:created_at) }, as: :adjustable, inverse_of: :adjustable, dependent: :destroy
71
87
  has_many :line_item_adjustments, through: :line_items, source: :adjustments
72
88
  has_many :shipment_adjustments, through: :shipments, source: :adjustments
73
- has_many :inventory_units, inverse_of: :order
74
- has_many :products, through: :variants
75
- has_many :variants, through: :line_items
76
- has_many :refunds, through: :payments
77
89
  has_many :all_adjustments,
78
90
  class_name: 'Spree::Adjustment',
79
91
  foreign_key: :order_id,
80
92
  dependent: :destroy,
81
93
  inverse_of: :order
82
-
83
- has_many :order_stock_locations, class_name: "Spree::OrderStockLocation"
84
- has_many :stock_locations, through: :order_stock_locations
85
-
86
94
  has_many :order_promotions, class_name: 'Spree::OrderPromotion'
87
95
  has_many :promotions, through: :order_promotions
88
96
 
89
- has_many :cartons, -> { distinct }, through: :inventory_units
90
- has_many :shipments, dependent: :destroy, inverse_of: :order do
91
- def states
92
- pluck(:state).uniq
93
- end
94
- end
97
+ # Payments
98
+ has_many :payments, dependent: :destroy, inverse_of: :order
99
+
100
+ # Returns
101
+ has_many :return_authorizations, dependent: :destroy, inverse_of: :order
102
+ has_many :reimbursements, inverse_of: :order
103
+ has_many :refunds, through: :payments
104
+
105
+ # Logging
106
+ has_many :state_changes, as: :stateful
107
+ belongs_to :created_by, class_name: Spree::UserClassHandle.new
108
+ belongs_to :approver, class_name: Spree::UserClassHandle.new
109
+ belongs_to :canceler, class_name: Spree::UserClassHandle.new
95
110
 
96
111
  accepts_nested_attributes_for :line_items
97
112
  accepts_nested_attributes_for :bill_address
@@ -111,6 +126,7 @@ module Spree
111
126
 
112
127
  validates :email, presence: true, if: :require_email
113
128
  validates :email, email: true, allow_blank: true
129
+ validates :guest_token, presence: { allow_nil: true }
114
130
  validates :number, presence: true, uniqueness: { allow_blank: true }
115
131
  validates :store_id, presence: true
116
132
 
@@ -134,7 +150,6 @@ module Spree
134
150
 
135
151
  # shows completed orders first, by their completed_at date, then uncompleted orders by their created_at
136
152
  scope :reverse_chronological, -> { order('spree_orders.completed_at IS NULL', completed_at: :desc, created_at: :desc) }
137
- scope :unreturned_exchange, -> { joins(:shipments).where('spree_orders.created_at > spree_shipments.created_at') }
138
153
 
139
154
  def self.by_customer(customer)
140
155
  joins(:user).where("#{Spree.user_class.table_name}.email" => customer)
@@ -220,7 +235,7 @@ module Spree
220
235
  # Returns the relevant zone (if any) to be used for taxation purposes.
221
236
  # Uses default tax zone unless there is a specific match
222
237
  def tax_zone
223
- Zone.match(tax_address) || Zone.default_tax
238
+ Spree::Zone.match(tax_address) || Spree::Zone.default_tax
224
239
  end
225
240
  deprecate tax_zone: "Please use Spree::Order#tax_address instead.",
226
241
  deprecator: Spree::Deprecation
@@ -235,7 +250,7 @@ module Spree
235
250
  end
236
251
 
237
252
  def updater
238
- @updater ||= OrderUpdater.new(self)
253
+ @updater ||= Spree::OrderUpdater.new(self)
239
254
  end
240
255
 
241
256
  def update!
@@ -381,12 +396,12 @@ module Spree
381
396
 
382
397
  def credit_cards
383
398
  credit_card_ids = payments.from_credit_card.pluck(:source_id).uniq
384
- CreditCard.where(id: credit_card_ids)
399
+ Spree::CreditCard.where(id: credit_card_ids)
385
400
  end
386
401
 
387
402
  def valid_credit_cards
388
403
  credit_card_ids = payments.from_credit_card.valid.pluck(:source_id).uniq
389
- CreditCard.where(id: credit_card_ids)
404
+ Spree::CreditCard.where(id: credit_card_ids)
390
405
  end
391
406
 
392
407
  # Finalizes an in progress order after checkout is complete.
@@ -418,7 +433,7 @@ module Spree
418
433
  end
419
434
 
420
435
  def deliver_order_confirmation_email
421
- OrderMailer.confirm_email(self).deliver_later
436
+ Spree::OrderMailer.confirm_email(self).deliver_later
422
437
  update_column(:confirmation_delivered, true)
423
438
  end
424
439
 
@@ -429,10 +444,10 @@ module Spree
429
444
 
430
445
  def available_payment_methods
431
446
  @available_payment_methods ||= Spree::PaymentMethod
447
+ .active
432
448
  .available_to_store(store)
433
449
  .available_to_users
434
- .active
435
- .sort_by(&:position)
450
+ .order(:position)
436
451
  end
437
452
 
438
453
  def insufficient_stock_lines
@@ -458,17 +473,14 @@ module Spree
458
473
 
459
474
  def empty!
460
475
  line_items.destroy_all
461
- updater.update_item_count
462
476
  adjustments.destroy_all
463
477
  shipments.destroy_all
464
478
 
465
- update_totals
466
- persist_totals
479
+ update!
467
480
  end
468
481
 
469
- def has_step?(step)
470
- checkout_steps.include?(step)
471
- end
482
+ alias_method :has_step?, :has_checkout_step?
483
+ deprecate has_step?: :has_checkout_step?, deprecator: Spree::Deprecation
472
484
 
473
485
  def state_changed(name)
474
486
  state = "#{name}_state"
@@ -509,8 +521,6 @@ module Spree
509
521
  end
510
522
 
511
523
  def create_proposed_shipments
512
- return shipments if unreturned_exchange?
513
-
514
524
  if completed?
515
525
  raise CannotRebuildShipments.new(Spree.t(:cannot_rebuild_shipments_order_completed))
516
526
  elsif shipments.any? { |s| !s.pending? }
@@ -559,9 +569,9 @@ module Spree
559
569
 
560
570
  def set_shipments_cost
561
571
  shipments.each(&:update_amounts)
562
- updater.update_shipment_total
563
- persist_totals
572
+ update!
564
573
  end
574
+ deprecate set_shipments_cost: :update!, deprecator: Spree::Deprecation
565
575
 
566
576
  def is_risky?
567
577
  payments.risky.count > 0
@@ -599,18 +609,6 @@ module Spree
599
609
  guest_token
600
610
  end
601
611
 
602
- def unreturned_exchange?
603
- # created_at - 1 is a hack to ensure that this doesn't blow up on MySQL,
604
- # records loaded from the DB on MySQL will have a precision of 1 second,
605
- # but records in memory may still have miliseconds on them, causing this
606
- # to be true where it shouldn't be.
607
- #
608
- # FIXME: find a better way to determine if an order is an unreturned
609
- # exchange
610
- shipment = shipments.first
611
- shipment.present? ? (shipment.created_at < created_at - 1) : false
612
- end
613
-
614
612
  def tax_total
615
613
  additional_tax_total + included_tax_total
616
614
  end
@@ -690,25 +688,90 @@ module Spree
690
688
  Spree::Money.new(total_available_store_credit - total_applicable_store_credit, { currency: currency })
691
689
  end
692
690
 
693
- def payments_attributes=(attributes)
694
- validate_payments_attributes(attributes)
695
- super(attributes)
691
+ def bill_address_attributes=(attributes)
692
+ self.bill_address = Spree::Address.immutable_merge(bill_address, attributes)
693
+ end
694
+
695
+ def ship_address_attributes=(attributes)
696
+ self.ship_address = Spree::Address.immutable_merge(ship_address, attributes)
696
697
  end
697
698
 
698
- def validate_payments_attributes(attributes)
699
- attributes = Array.wrap(attributes)
700
- # Ensure the payment methods specified are allowed for this user
701
- payment_methods = Spree::PaymentMethod.where(id: available_payment_methods)
702
- attributes.each do |payment_attributes|
703
- payment_method_id = payment_attributes[:payment_method_id]
699
+ def assign_default_addresses!
700
+ if user
701
+ # this is one of 2 places still using User#bill_address
702
+ self.bill_address ||= user.bill_address if user.bill_address.try!(:valid?)
703
+ # Skip setting ship address if order doesn't have a delivery checkout step
704
+ # to avoid triggering validations on shipping address
705
+ self.ship_address ||= user.ship_address if user.ship_address.try!(:valid?) && checkout_steps.include?("delivery")
706
+ end
707
+ end
704
708
 
705
- # raise RecordNotFound unless it is an allowed payment method
706
- payment_methods.find(payment_method_id) if payment_method_id
709
+ def persist_user_address!
710
+ if !temporary_address && user && user.respond_to?(:persist_order_address) && bill_address_id
711
+ user.persist_order_address(self)
707
712
  end
708
713
  end
709
714
 
715
+ def add_payment_sources_to_wallet
716
+ Spree::Config.
717
+ add_payment_sources_to_wallet_class.new(self).
718
+ add_to_wallet
719
+ end
720
+ alias_method :persist_user_credit_card, :add_payment_sources_to_wallet
721
+ deprecate persist_user_credit_card: :add_payment_sources_to_wallet, deprecator: Spree::Deprecation
722
+
723
+ def add_default_payment_from_wallet
724
+ builder = Spree::Config.default_payment_builder_class.new(self)
725
+
726
+ if payment = builder.build
727
+ payments << payment
728
+
729
+ if bill_address.nil?
730
+ # this is one of 2 places still using User#bill_address
731
+ self.bill_address = payment.source.try(:address) ||
732
+ user.bill_address
733
+ end
734
+ end
735
+ end
736
+ alias_method :assign_default_credit_card, :add_default_payment_from_wallet
737
+ deprecate assign_default_credit_card: :add_default_payment_from_wallet, deprecator: Spree::Deprecation
738
+
710
739
  private
711
740
 
741
+ def process_payments_before_complete
742
+ return if !payment_required?
743
+
744
+ if payments.valid.empty?
745
+ errors.add(:base, Spree.t(:no_payment_found))
746
+ return false
747
+ end
748
+
749
+ if process_payments!
750
+ true
751
+ else
752
+ saved_errors = errors[:base]
753
+ payment_failed!
754
+ saved_errors.each { |error| errors.add(:base, error) }
755
+ false
756
+ end
757
+ end
758
+
759
+ # In case a existing credit card is provided it needs to build the payment
760
+ # attributes from scratch so we can set the amount. example payload:
761
+ #
762
+ # {
763
+ # "order": {
764
+ # "existing_card": "2"
765
+ # }
766
+ # }
767
+ #
768
+ def update_params_payment_source
769
+ if @updating_params[:order] && (@updating_params[:order][:payments_attributes] || @updating_params[:order][:existing_card])
770
+ @updating_params[:order][:payments_attributes] ||= [{}]
771
+ @updating_params[:order][:payments_attributes].first[:amount] = total
772
+ end
773
+ end
774
+
712
775
  def associate_store
713
776
  self.store ||= Spree::Store.default
714
777
  end
@@ -723,7 +786,7 @@ module Spree
723
786
  end
724
787
 
725
788
  def ensure_inventory_units
726
- if has_step?("delivery")
789
+ if has_checkout_step?("delivery")
727
790
  inventory_validator = Spree::Stock::InventoryValidator.new
728
791
 
729
792
  errors = line_items.map { |line_item| inventory_validator.validate(line_item) }.compact
@@ -732,9 +795,12 @@ module Spree
732
795
  end
733
796
 
734
797
  def ensure_promotions_eligible
735
- updater.update_adjustment_total
736
- if promo_total_changed?
798
+ adjustment_changed = all_adjustments.eligible.promotion.any? do |adjustment|
799
+ !adjustment.calculate_eligibility
800
+ end
801
+ if adjustment_changed
737
802
  restart_checkout_flow
803
+ update!
738
804
  errors.add(:base, Spree.t(:promotion_total_changed_before_complete))
739
805
  end
740
806
  errors.empty?
@@ -770,7 +836,7 @@ module Spree
770
836
  end
771
837
 
772
838
  def send_cancel_email
773
- OrderMailer.cancel_email(self).deliver_later
839
+ Spree::OrderMailer.cancel_email(self).deliver_later
774
840
  end
775
841
 
776
842
  def after_resume
@@ -80,7 +80,7 @@ module Spree
80
80
  end
81
81
 
82
82
  def order_updater
83
- @updater ||= OrderUpdater.new(order)
83
+ @updater ||= Spree::OrderUpdater.new(order)
84
84
  end
85
85
 
86
86
  def reload_totals
@@ -18,13 +18,13 @@ module Spree
18
18
  def verify(shipment = nil)
19
19
  if order.completed? || shipment.present?
20
20
 
21
- if inventory_units.size < line_item.quantity
22
- quantity = line_item.quantity - inventory_units.size
23
-
24
- shipment = determine_target_shipment unless shipment
25
- add_to_shipment(shipment, quantity)
26
- elsif inventory_units.size > line_item.quantity
27
- remove(inventory_units, shipment)
21
+ existing_quantity = inventory_units.count
22
+ desired_quantity = line_item.quantity - existing_quantity
23
+ if desired_quantity > 0
24
+ shipment ||= determine_target_shipment
25
+ add_to_shipment(shipment, desired_quantity)
26
+ elsif desired_quantity < 0
27
+ remove(-desired_quantity, shipment)
28
28
  end
29
29
  end
30
30
  end
@@ -35,9 +35,7 @@ module Spree
35
35
 
36
36
  private
37
37
 
38
- def remove(item_units, shipment = nil)
39
- quantity = item_units.size - line_item.quantity
40
-
38
+ def remove(quantity, shipment = nil)
41
39
  if shipment.present?
42
40
  remove_from_shipment(shipment, quantity)
43
41
  else
@@ -100,7 +98,9 @@ module Spree
100
98
  removed_quantity += 1
101
99
  end
102
100
 
103
- shipment.destroy if shipment.inventory_units.count == 0
101
+ if shipment.inventory_units.count.zero?
102
+ order.shipments.destroy(shipment)
103
+ end
104
104
 
105
105
  # removing this from shipment, and adding to stock_location
106
106
  if order.completed?
@@ -14,6 +14,8 @@ module Spree
14
14
  validates :promotion, presence: true
15
15
  validates :promotion_code, presence: true, if: :require_promotion_code?
16
16
 
17
+ self.whitelisted_ransackable_associations = %w[promotion_code]
18
+
17
19
  private
18
20
 
19
21
  def require_promotion_code?
@@ -14,17 +14,10 @@ module Spree
14
14
  # Assign the attributes to the order and save the order
15
15
  # @return true if saved, otherwise false and errors will be set on the order
16
16
  def apply
17
- order.validate_payments_attributes(@payments_attributes)
18
-
19
17
  assign_order_attributes
20
18
  assign_payments_attributes
21
19
 
22
- if order.save
23
- order.set_shipments_cost if order.shipments.any?
24
- true
25
- else
26
- false
27
- end
20
+ order.save
28
21
  end
29
22
 
30
23
  private
@@ -17,6 +17,7 @@ module Spree
17
17
  def update
18
18
  @order.transaction do
19
19
  update_item_count
20
+ update_shipment_amounts
20
21
  update_totals
21
22
  if order.completed?
22
23
  update_payment_state
@@ -32,6 +33,65 @@ module Spree
32
33
  update_hooks.each { |hook| order.send hook }
33
34
  end
34
35
 
36
+ # Updates the +shipment_state+ attribute according to the following logic:
37
+ #
38
+ # shipped when all Shipments are in the "shipped" state
39
+ # partial when at least one Shipment has a state of "shipped" and there is another Shipment with a state other than "shipped"
40
+ # or there are InventoryUnits associated with the order that have a state of "sold" but are not associated with a Shipment.
41
+ # ready when all Shipments are in the "ready" state
42
+ # backorder when there is backordered inventory associated with an order
43
+ # pending when all Shipments are in the "pending" state
44
+ #
45
+ # The +shipment_state+ value helps with reporting, etc. since it provides a quick and easy way to locate Orders needing attention.
46
+ def update_shipment_state
47
+ if order.backordered?
48
+ order.shipment_state = 'backorder'
49
+ else
50
+ # get all the shipment states for this order
51
+ shipment_states = shipments.states
52
+ if shipment_states.size > 1
53
+ # multiple shiment states means it's most likely partially shipped
54
+ order.shipment_state = 'partial'
55
+ else
56
+ # will return nil if no shipments are found
57
+ order.shipment_state = shipment_states.first
58
+ # TODO: inventory unit states?
59
+ # if order.shipment_state && order.inventory_units.where(:shipment_id => nil).exists?
60
+ # shipments exist but there are unassigned inventory units
61
+ # order.shipment_state = 'partial'
62
+ # end
63
+ end
64
+ end
65
+
66
+ order.state_changed('shipment')
67
+ order.shipment_state
68
+ end
69
+
70
+ # Updates the +payment_state+ attribute according to the following logic:
71
+ #
72
+ # paid when +payment_total+ is equal to +total+
73
+ # balance_due when +payment_total+ is less than +total+
74
+ # credit_owed when +payment_total+ is greater than +total+
75
+ # failed when most recent payment is in the failed state
76
+ #
77
+ # The +payment_state+ value helps with reporting, etc. since it provides a quick and easy way to locate Orders needing attention.
78
+ def update_payment_state
79
+ last_state = order.payment_state
80
+ if payments.present? && payments.valid.size == 0 && order.outstanding_balance != 0
81
+ order.payment_state = 'failed'
82
+ elsif order.state == 'canceled' && order.payment_total == 0
83
+ order.payment_state = 'void'
84
+ else
85
+ order.payment_state = 'balance_due' if order.outstanding_balance > 0
86
+ order.payment_state = 'credit_owed' if order.outstanding_balance < 0
87
+ order.payment_state = 'paid' if !order.outstanding_balance?
88
+ end
89
+ order.state_changed('payment') if last_state != order.payment_state
90
+ order.payment_state
91
+ end
92
+
93
+ private
94
+
35
95
  # This will update and select the best promotion adjustment, update tax
36
96
  # adjustments, update cancellation adjustments, and then update the total
37
97
  # fields (promo_total, included_tax_total, additional_tax_total, and
@@ -64,13 +124,16 @@ module Spree
64
124
  update_adjustment_total
65
125
  end
66
126
 
127
+ def update_shipment_amounts
128
+ shipments.each do |shipment|
129
+ shipment.update_amounts
130
+ end
131
+ end
132
+
67
133
  # give each of the shipments a chance to update themselves
68
134
  def update_shipments
69
135
  shipments.each do |shipment|
70
- next unless shipment.persisted?
71
136
  shipment.update!(order)
72
- shipment.refresh_rates
73
- shipment.update_amounts
74
137
  end
75
138
  end
76
139
 
@@ -102,7 +165,7 @@ module Spree
102
165
  end
103
166
 
104
167
  def update_item_count
105
- order.item_count = quantity
168
+ order.item_count = line_items.to_a.sum(&:quantity)
106
169
  end
107
170
 
108
171
  def update_item_total
@@ -114,65 +177,6 @@ module Spree
114
177
  order.save!(validate: false)
115
178
  end
116
179
 
117
- # Updates the +shipment_state+ attribute according to the following logic:
118
- #
119
- # shipped when all Shipments are in the "shipped" state
120
- # partial when at least one Shipment has a state of "shipped" and there is another Shipment with a state other than "shipped"
121
- # or there are InventoryUnits associated with the order that have a state of "sold" but are not associated with a Shipment.
122
- # ready when all Shipments are in the "ready" state
123
- # backorder when there is backordered inventory associated with an order
124
- # pending when all Shipments are in the "pending" state
125
- #
126
- # The +shipment_state+ value helps with reporting, etc. since it provides a quick and easy way to locate Orders needing attention.
127
- def update_shipment_state
128
- if order.backordered?
129
- order.shipment_state = 'backorder'
130
- else
131
- # get all the shipment states for this order
132
- shipment_states = shipments.states
133
- if shipment_states.size > 1
134
- # multiple shiment states means it's most likely partially shipped
135
- order.shipment_state = 'partial'
136
- else
137
- # will return nil if no shipments are found
138
- order.shipment_state = shipment_states.first
139
- # TODO: inventory unit states?
140
- # if order.shipment_state && order.inventory_units.where(:shipment_id => nil).exists?
141
- # shipments exist but there are unassigned inventory units
142
- # order.shipment_state = 'partial'
143
- # end
144
- end
145
- end
146
-
147
- order.state_changed('shipment')
148
- order.shipment_state
149
- end
150
-
151
- # Updates the +payment_state+ attribute according to the following logic:
152
- #
153
- # paid when +payment_total+ is equal to +total+
154
- # balance_due when +payment_total+ is less than +total+
155
- # credit_owed when +payment_total+ is greater than +total+
156
- # failed when most recent payment is in the failed state
157
- #
158
- # The +payment_state+ value helps with reporting, etc. since it provides a quick and easy way to locate Orders needing attention.
159
- def update_payment_state
160
- last_state = order.payment_state
161
- if payments.present? && payments.valid.size == 0 && order.outstanding_balance != 0
162
- order.payment_state = 'failed'
163
- elsif order.state == 'canceled' && order.payment_total == 0
164
- order.payment_state = 'void'
165
- else
166
- order.payment_state = 'balance_due' if order.outstanding_balance > 0
167
- order.payment_state = 'credit_owed' if order.outstanding_balance < 0
168
- order.payment_state = 'paid' if !order.outstanding_balance?
169
- end
170
- order.state_changed('payment') if last_state != order.payment_state
171
- order.payment_state
172
- end
173
-
174
- private
175
-
176
180
  def round_money(n)
177
181
  (n * 100).round / 100.0
178
182
  end
@@ -40,7 +40,6 @@ module Spree
40
40
 
41
41
  validates :amount, numericality: true
42
42
  validates :source, presence: true, if: :source_required?
43
- validates :payment_method, presence: true
44
43
 
45
44
  default_scope -> { order(:created_at) }
46
45