diff --git a/app/models/spree/order_updater_decorator.rb b/app/models/spree/order_updater_decorator.rb new file mode 100644 index 0000000000..ab1d4eaf26 --- /dev/null +++ b/app/models/spree/order_updater_decorator.rb @@ -0,0 +1,41 @@ +module Spree + OrderUpdater.class_eval do + # TODO: This logic adapted from Spree 2.4, remove when we get there + # Handles state updating in a much more logical way than < 2.4 + # Specifically, doesn't depend on payments.last to determine payment state + # Also swapped: == 0 for .zero?, .size == 0 for empty? and .size > 0 for !empty? + # See: + # https://github.com/spree/spree/commit/38b8456183d11fc1e00e395e7c9154c76ef65b85 + # https://github.com/spree/spree/commit/7b264acff7824f5b3dc6651c106631d8f30b147a + def update_payment_state + last_state = order.payment_state + if payments.present? && payments.valid.empty? + order.payment_state = 'failed' + elsif order.state == 'canceled' && order.payment_total.zero? + order.payment_state = 'void' + else + # This part added so that we don't need to override order.outstanding_balance + balance = order.outstanding_balance + balance = -1 * order.payment_total if canceled_and_paid_for? + order.payment_state = 'balance_due' if balance > 0 + order.payment_state = 'credit_owed' if balance < 0 + order.payment_state = 'paid' if balance.zero? + + # Original logic + # order.payment_state = 'balance_due' if order.outstanding_balance > 0 + # order.payment_state = 'credit_owed' if order.outstanding_balance < 0 + # order.payment_state = 'paid' if !order.outstanding_balance? + end + order.state_changed('payment') if last_state != order.payment_state + order.payment_state + end + + private + + # Taken from order.outstanding_balance in Spree 2.4 + # See: https://github.com/spree/spree/commit/7b264acff7824f5b3dc6651c106631d8f30b147a + def canceled_and_paid_for? + order.canceled? && order.payments.present? && !order.payments.completed.empty? + end + end +end diff --git a/spec/models/spree/order_updater_spec.rb b/spec/models/spree/order_updater_spec.rb new file mode 100644 index 0000000000..50ab49a8c7 --- /dev/null +++ b/spec/models/spree/order_updater_spec.rb @@ -0,0 +1,91 @@ +require 'spec_helper' + +describe Spree::OrderUpdater do + # Copied pretty much verbatim from Spree 2.4. Remove this file once we get there, + # assuming the unchanged 2.4 logic still works for us. + # Only changes are stubs of :empty? instead of :size + context "updating payment state" do + let(:order) { Spree::Order.new } + let(:updater) { order.updater } + + it "is failed if no valid payments" do + order.stub_chain(:payments, :valid, :empty?).and_return(true) + + updater.update_payment_state + order.payment_state.should == 'failed' + end + + context "payment total is greater than order total" do + it "is credit_owed" do + order.payment_total = 2 + order.total = 1 + + expect { + updater.update_payment_state + }.to change { order.payment_state }.to 'credit_owed' + end + end + + context "order total is greater than payment total" do + it "is credit_owed" do + order.payment_total = 1 + order.total = 2 + + expect { + updater.update_payment_state + }.to change { order.payment_state }.to 'balance_due' + end + end + + context "order total equals payment total" do + it "is paid" do + order.payment_total = 30 + order.total = 30 + + expect { + updater.update_payment_state + }.to change { order.payment_state }.to 'paid' + end + end + + context "order is canceled" do + before do + order.state = 'canceled' + end + + context "and is still unpaid" do + it "is void" do + order.payment_total = 0 + order.total = 30 + expect { + updater.update_payment_state + }.to change { order.payment_state }.to 'void' + end + end + + context "and is paid" do + it "is credit_owed" do + order.payment_total = 30 + order.total = 30 + order.stub_chain(:payments, :valid, :empty?).and_return(false) + order.stub_chain(:payments, :completed, :empty?).and_return(false) + expect { + updater.update_payment_state + }.to change { order.payment_state }.to 'credit_owed' + end + end + + context "and payment is refunded" do + it "is void" do + order.payment_total = 0 + order.total = 30 + order.stub_chain(:payments, :valid, :empty?).and_return(false) + order.stub_chain(:payments, :completed, :empty?).and_return(false) + expect { + updater.update_payment_state + }.to change { order.payment_state }.to 'void' + end + end + end + end +end