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
@@ -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