mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-11 23:17:48 +00:00
Unnest OrderManagement::Order declaration in two module declaration
This commit is contained in:
@@ -1,200 +1,202 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module OrderManagement::Order
|
||||
class Updater
|
||||
attr_reader :order
|
||||
delegate :payments, :line_items, :adjustments, :shipments, :update_hooks, to: :order
|
||||
module OrderManagement
|
||||
module Order
|
||||
class Updater
|
||||
attr_reader :order
|
||||
delegate :payments, :line_items, :adjustments, :shipments, :update_hooks, to: :order
|
||||
|
||||
def initialize(order)
|
||||
@order = order
|
||||
end
|
||||
|
||||
# This is a multi-purpose method for processing logic related to changes in the Order.
|
||||
# It is meant to be called from various observers so that the Order is aware of changes
|
||||
# that affect totals and other values stored in the Order.
|
||||
#
|
||||
# This method should never do anything to the Order that results in a save call on the
|
||||
# object with callbacks (otherwise you will end up in an infinite recursion as the
|
||||
# associations try to save and then in turn try to call +update!+ again.)
|
||||
def update
|
||||
update_totals
|
||||
|
||||
if order.completed?
|
||||
update_payment_state
|
||||
|
||||
# give each of the shipments a chance to update themselves
|
||||
shipments.each { |shipment| shipment.update!(order) }
|
||||
update_shipment_state
|
||||
def initialize(order)
|
||||
@order = order
|
||||
end
|
||||
|
||||
update_all_adjustments
|
||||
# update totals a second time in case updated adjustments have an effect on the total
|
||||
update_totals
|
||||
# This is a multi-purpose method for processing logic related to changes in the Order.
|
||||
# It is meant to be called from various observers so that the Order is aware of changes
|
||||
# that affect totals and other values stored in the Order.
|
||||
#
|
||||
# This method should never do anything to the Order that results in a save call on the
|
||||
# object with callbacks (otherwise you will end up in an infinite recursion as the
|
||||
# associations try to save and then in turn try to call +update!+ again.)
|
||||
def update
|
||||
update_totals
|
||||
|
||||
order.update_attributes_without_callbacks(
|
||||
{
|
||||
payment_state: order.payment_state,
|
||||
shipment_state: order.shipment_state,
|
||||
item_total: order.item_total,
|
||||
adjustment_total: order.adjustment_total,
|
||||
payment_total: order.payment_total,
|
||||
total: order.total
|
||||
}
|
||||
)
|
||||
if order.completed?
|
||||
update_payment_state
|
||||
|
||||
run_hooks
|
||||
end
|
||||
# give each of the shipments a chance to update themselves
|
||||
shipments.each { |shipment| shipment.update!(order) }
|
||||
update_shipment_state
|
||||
end
|
||||
|
||||
def run_hooks
|
||||
update_hooks.each { |hook| order.__send__(hook) }
|
||||
end
|
||||
update_all_adjustments
|
||||
# update totals a second time in case updated adjustments have an effect on the total
|
||||
update_totals
|
||||
|
||||
# Updates the following Order total values:
|
||||
#
|
||||
# - payment_total - the total value of all finalized Payments (excluding non-finalized Payments)
|
||||
# - item_total - the total value of all LineItems
|
||||
# - adjustment_total - the total value of all adjustments
|
||||
# - total - the "order total". This is equivalent to item_total plus adjustment_total
|
||||
def update_totals
|
||||
order.payment_total = payments.completed.map(&:amount).sum
|
||||
order.item_total = line_items.map(&:amount).sum
|
||||
order.adjustment_total = adjustments.eligible.map(&:amount).sum
|
||||
order.total = order.item_total + order.adjustment_total
|
||||
end
|
||||
order.update_attributes_without_callbacks(
|
||||
{
|
||||
payment_state: order.payment_state,
|
||||
shipment_state: order.shipment_state,
|
||||
item_total: order.item_total,
|
||||
adjustment_total: order.adjustment_total,
|
||||
payment_total: order.payment_total,
|
||||
total: order.total
|
||||
}
|
||||
)
|
||||
|
||||
# Updates the +shipment_state+ attribute according to the following logic:
|
||||
#
|
||||
# - shipped - when all Shipments are in the "shipped" state
|
||||
# - partial - when 1. at least one Shipment has a state of "shipped"
|
||||
# and there is another Shipment with a state other than "shipped"
|
||||
# or 2. there are InventoryUnits associated with the order that
|
||||
# have a state of "sold" but are not associated with a Shipment
|
||||
# - ready - when all Shipments are in the "ready" state
|
||||
# - backorder - when there is backordered inventory associated with an order
|
||||
# - pending - when all Shipments are in the "pending" state
|
||||
#
|
||||
# The +shipment_state+ value helps with reporting, etc. since it provides a quick and easy way
|
||||
# to locate Orders needing attention.
|
||||
def update_shipment_state
|
||||
if order.backordered?
|
||||
order.shipment_state = 'backorder'
|
||||
else
|
||||
# get all the shipment states for this order
|
||||
shipment_states = shipments.states
|
||||
if shipment_states.size > 1
|
||||
# multiple shiment states means it's most likely partially shipped
|
||||
order.shipment_state = 'partial'
|
||||
run_hooks
|
||||
end
|
||||
|
||||
def run_hooks
|
||||
update_hooks.each { |hook| order.__send__(hook) }
|
||||
end
|
||||
|
||||
# Updates the following Order total values:
|
||||
#
|
||||
# - payment_total - the total value of all finalized Payments (excluding non-finalized Payments)
|
||||
# - item_total - the total value of all LineItems
|
||||
# - adjustment_total - the total value of all adjustments
|
||||
# - total - the "order total". This is equivalent to item_total plus adjustment_total
|
||||
def update_totals
|
||||
order.payment_total = payments.completed.map(&:amount).sum
|
||||
order.item_total = line_items.map(&:amount).sum
|
||||
order.adjustment_total = adjustments.eligible.map(&:amount).sum
|
||||
order.total = order.item_total + order.adjustment_total
|
||||
end
|
||||
|
||||
# Updates the +shipment_state+ attribute according to the following logic:
|
||||
#
|
||||
# - shipped - when all Shipments are in the "shipped" state
|
||||
# - partial - when 1. at least one Shipment has a state of "shipped"
|
||||
# and there is another Shipment with a state other than "shipped"
|
||||
# or 2. there are InventoryUnits associated with the order that
|
||||
# have a state of "sold" but are not associated with a Shipment
|
||||
# - ready - when all Shipments are in the "ready" state
|
||||
# - backorder - when there is backordered inventory associated with an order
|
||||
# - pending - when all Shipments are in the "pending" state
|
||||
#
|
||||
# The +shipment_state+ value helps with reporting, etc. since it provides a quick and easy way
|
||||
# to locate Orders needing attention.
|
||||
def update_shipment_state
|
||||
if order.backordered?
|
||||
order.shipment_state = 'backorder'
|
||||
else
|
||||
# will return nil if no shipments are found
|
||||
order.shipment_state = shipment_states.first
|
||||
# TODO inventory unit states?
|
||||
# if order.shipment_state && order.inventory_units.where(:shipment_id => nil).exists?
|
||||
# shipments exist but there are unassigned inventory units
|
||||
# order.shipment_state = 'partial'
|
||||
# end
|
||||
# get all the shipment states for this order
|
||||
shipment_states = shipments.states
|
||||
if shipment_states.size > 1
|
||||
# multiple shiment states means it's most likely partially shipped
|
||||
order.shipment_state = 'partial'
|
||||
else
|
||||
# will return nil if no shipments are found
|
||||
order.shipment_state = shipment_states.first
|
||||
# TODO inventory unit states?
|
||||
# if order.shipment_state && order.inventory_units.where(:shipment_id => nil).exists?
|
||||
# shipments exist but there are unassigned inventory units
|
||||
# order.shipment_state = 'partial'
|
||||
# end
|
||||
end
|
||||
end
|
||||
|
||||
order.state_changed('shipment')
|
||||
end
|
||||
|
||||
# Updates the +payment_state+ attribute according to the following logic:
|
||||
#
|
||||
# - paid - when +payment_total+ is equal to +total+
|
||||
# - balance_due - when +payment_total+ is less than +total+
|
||||
# - credit_owed - when +payment_total+ is greater than +total+
|
||||
# - failed - when most recent payment is in the failed state
|
||||
#
|
||||
# The +payment_state+ value helps with reporting, etc. since it provides a quick and easy way
|
||||
# to locate Orders needing attention.
|
||||
def update_payment_state
|
||||
last_payment_state = order.payment_state
|
||||
|
||||
order.payment_state = infer_payment_state
|
||||
track_payment_state_change(last_payment_state)
|
||||
|
||||
order.payment_state
|
||||
end
|
||||
|
||||
def update_all_adjustments
|
||||
order.adjustments.reload.each(&:update!)
|
||||
end
|
||||
|
||||
def before_save_hook
|
||||
shipping_address_from_distributor
|
||||
end
|
||||
|
||||
# Sets the distributor's address as shipping address of the order for those
|
||||
# shipments using a shipping method that doesn't require address, such us
|
||||
# a pickup.
|
||||
def shipping_address_from_distributor
|
||||
return if order.shipping_method.blank? || order.shipping_method.require_ship_address
|
||||
|
||||
order.ship_address = order.address_from_distributor
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def round_money(value)
|
||||
(value * 100).round / 100.0
|
||||
end
|
||||
|
||||
def infer_payment_state
|
||||
if failed_payments?
|
||||
'failed'
|
||||
elsif canceled_and_not_paid_for?
|
||||
'void'
|
||||
else
|
||||
infer_payment_state_from_balance
|
||||
end
|
||||
end
|
||||
|
||||
order.state_changed('shipment')
|
||||
end
|
||||
def infer_payment_state_from_balance
|
||||
# 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?
|
||||
|
||||
# Updates the +payment_state+ attribute according to the following logic:
|
||||
#
|
||||
# - paid - when +payment_total+ is equal to +total+
|
||||
# - balance_due - when +payment_total+ is less than +total+
|
||||
# - credit_owed - when +payment_total+ is greater than +total+
|
||||
# - failed - when most recent payment is in the failed state
|
||||
#
|
||||
# The +payment_state+ value helps with reporting, etc. since it provides a quick and easy way
|
||||
# to locate Orders needing attention.
|
||||
def update_payment_state
|
||||
last_payment_state = order.payment_state
|
||||
|
||||
order.payment_state = infer_payment_state
|
||||
track_payment_state_change(last_payment_state)
|
||||
|
||||
order.payment_state
|
||||
end
|
||||
|
||||
def update_all_adjustments
|
||||
order.adjustments.reload.each(&:update!)
|
||||
end
|
||||
|
||||
def before_save_hook
|
||||
shipping_address_from_distributor
|
||||
end
|
||||
|
||||
# Sets the distributor's address as shipping address of the order for those
|
||||
# shipments using a shipping method that doesn't require address, such us
|
||||
# a pickup.
|
||||
def shipping_address_from_distributor
|
||||
return if order.shipping_method.blank? || order.shipping_method.require_ship_address
|
||||
|
||||
order.ship_address = order.address_from_distributor
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def round_money(value)
|
||||
(value * 100).round / 100.0
|
||||
end
|
||||
|
||||
def infer_payment_state
|
||||
if failed_payments?
|
||||
'failed'
|
||||
elsif canceled_and_not_paid_for?
|
||||
'void'
|
||||
else
|
||||
infer_payment_state_from_balance
|
||||
infer_state(balance)
|
||||
end
|
||||
end
|
||||
|
||||
def infer_payment_state_from_balance
|
||||
# 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?
|
||||
|
||||
infer_state(balance)
|
||||
end
|
||||
|
||||
def infer_state(balance)
|
||||
if balance > 0
|
||||
'balance_due'
|
||||
elsif balance < 0
|
||||
'credit_owed'
|
||||
elsif balance.zero?
|
||||
'paid'
|
||||
def infer_state(balance)
|
||||
if balance > 0
|
||||
'balance_due'
|
||||
elsif balance < 0
|
||||
'credit_owed'
|
||||
elsif balance.zero?
|
||||
'paid'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Tracks the state transition through a state_change for this order. It
|
||||
# does so until the last state is reached. That is, when the infered next
|
||||
# state is the same as the order has now.
|
||||
#
|
||||
# @param last_payment_state [String]
|
||||
def track_payment_state_change(last_payment_state)
|
||||
return if last_payment_state == order.payment_state
|
||||
# Tracks the state transition through a state_change for this order. It
|
||||
# does so until the last state is reached. That is, when the infered next
|
||||
# state is the same as the order has now.
|
||||
#
|
||||
# @param last_payment_state [String]
|
||||
def track_payment_state_change(last_payment_state)
|
||||
return if last_payment_state == order.payment_state
|
||||
|
||||
order.state_changed('payment')
|
||||
end
|
||||
order.state_changed('payment')
|
||||
end
|
||||
|
||||
# Taken from order.outstanding_balance in Spree 2.4
|
||||
# See: https://github.com/spree/spree/commit/7b264acff7824f5b3dc6651c106631d8f30b147a
|
||||
def canceled_and_paid_for?
|
||||
order.canceled? && paid?
|
||||
end
|
||||
# Taken from order.outstanding_balance in Spree 2.4
|
||||
# See: https://github.com/spree/spree/commit/7b264acff7824f5b3dc6651c106631d8f30b147a
|
||||
def canceled_and_paid_for?
|
||||
order.canceled? && paid?
|
||||
end
|
||||
|
||||
def canceled_and_not_paid_for?
|
||||
order.state == 'canceled' && order.payment_total.zero?
|
||||
end
|
||||
def canceled_and_not_paid_for?
|
||||
order.state == 'canceled' && order.payment_total.zero?
|
||||
end
|
||||
|
||||
def paid?
|
||||
payments.present? && !payments.completed.empty?
|
||||
end
|
||||
def paid?
|
||||
payments.present? && !payments.completed.empty?
|
||||
end
|
||||
|
||||
def failed_payments?
|
||||
payments.present? && payments.valid.empty?
|
||||
def failed_payments?
|
||||
payments.present? && payments.valid.empty?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,289 +2,291 @@
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
module OrderManagement::Order
|
||||
describe Updater do
|
||||
let(:order) { build(:order) }
|
||||
let(:updater) { OrderManagement::Order::Updater.new(order) }
|
||||
module OrderManagement
|
||||
module Order
|
||||
describe Updater do
|
||||
let(:order) { build(:order) }
|
||||
let(:updater) { OrderManagement::Order::Updater.new(order) }
|
||||
|
||||
before { allow(order).to receive(:backordered?) { false } }
|
||||
before { allow(order).to receive(:backordered?) { false } }
|
||||
|
||||
it "updates totals" do
|
||||
payments = [double(amount: 5), double(amount: 5)]
|
||||
allow(order).to receive_message_chain(:payments, :completed).and_return(payments)
|
||||
it "updates totals" do
|
||||
payments = [double(amount: 5), double(amount: 5)]
|
||||
allow(order).to receive_message_chain(:payments, :completed).and_return(payments)
|
||||
|
||||
line_items = [double(amount: 10), double(amount: 20)]
|
||||
allow(order).to receive_messages line_items: line_items
|
||||
line_items = [double(amount: 10), double(amount: 20)]
|
||||
allow(order).to receive_messages line_items: line_items
|
||||
|
||||
adjustments = [double(amount: 10), double(amount: -20)]
|
||||
allow(order).to receive_message_chain(:adjustments, :eligible).and_return(adjustments)
|
||||
adjustments = [double(amount: 10), double(amount: -20)]
|
||||
allow(order).to receive_message_chain(:adjustments, :eligible).and_return(adjustments)
|
||||
|
||||
updater.update_totals
|
||||
expect(order.payment_total).to eq 10
|
||||
expect(order.item_total).to eq 30
|
||||
expect(order.adjustment_total).to eq(-10)
|
||||
expect(order.total).to eq 20
|
||||
end
|
||||
|
||||
context "updating shipment state" do
|
||||
before do
|
||||
allow(order).to receive_message_chain(:shipments, :shipped, :count).and_return(0)
|
||||
allow(order).to receive_message_chain(:shipments, :ready, :count).and_return(0)
|
||||
allow(order).to receive_message_chain(:shipments, :pending, :count).and_return(0)
|
||||
updater.update_totals
|
||||
expect(order.payment_total).to eq 10
|
||||
expect(order.item_total).to eq 30
|
||||
expect(order.adjustment_total).to eq(-10)
|
||||
expect(order.total).to eq 20
|
||||
end
|
||||
|
||||
it "is backordered" do
|
||||
allow(order).to receive(:backordered?) { true }
|
||||
updater.update_shipment_state
|
||||
context "updating shipment state" do
|
||||
before do
|
||||
allow(order).to receive_message_chain(:shipments, :shipped, :count).and_return(0)
|
||||
allow(order).to receive_message_chain(:shipments, :ready, :count).and_return(0)
|
||||
allow(order).to receive_message_chain(:shipments, :pending, :count).and_return(0)
|
||||
end
|
||||
|
||||
expect(order.shipment_state).to eq 'backorder'
|
||||
end
|
||||
|
||||
it "is nil" do
|
||||
allow(order).to receive_message_chain(:shipments, :states).and_return([])
|
||||
allow(order).to receive_message_chain(:shipments, :count).and_return(0)
|
||||
|
||||
updater.update_shipment_state
|
||||
expect(order.shipment_state).to be_nil
|
||||
end
|
||||
|
||||
["shipped", "ready", "pending"].each do |state|
|
||||
it "is #{state}" do
|
||||
allow(order).to receive_message_chain(:shipments, :states).and_return([state])
|
||||
it "is backordered" do
|
||||
allow(order).to receive(:backordered?) { true }
|
||||
updater.update_shipment_state
|
||||
expect(order.shipment_state).to eq state.to_s
|
||||
|
||||
expect(order.shipment_state).to eq 'backorder'
|
||||
end
|
||||
|
||||
it "is nil" do
|
||||
allow(order).to receive_message_chain(:shipments, :states).and_return([])
|
||||
allow(order).to receive_message_chain(:shipments, :count).and_return(0)
|
||||
|
||||
updater.update_shipment_state
|
||||
expect(order.shipment_state).to be_nil
|
||||
end
|
||||
|
||||
["shipped", "ready", "pending"].each do |state|
|
||||
it "is #{state}" do
|
||||
allow(order).to receive_message_chain(:shipments, :states).and_return([state])
|
||||
updater.update_shipment_state
|
||||
expect(order.shipment_state).to eq state.to_s
|
||||
end
|
||||
end
|
||||
|
||||
it "is partial" do
|
||||
allow(order).to receive_message_chain(:shipments, :states).and_return(["pending", "ready"])
|
||||
updater.update_shipment_state
|
||||
expect(order.shipment_state).to eq 'partial'
|
||||
end
|
||||
end
|
||||
|
||||
it "is partial" do
|
||||
allow(order).to receive_message_chain(:shipments, :states).and_return(["pending", "ready"])
|
||||
updater.update_shipment_state
|
||||
expect(order.shipment_state).to eq 'partial'
|
||||
end
|
||||
end
|
||||
it "state change" do
|
||||
order = create(:order)
|
||||
order.shipment_state = 'shipped'
|
||||
state_changes = double
|
||||
allow(order).to receive(:state_changes) { state_changes }
|
||||
expect(state_changes).to receive(:create).with(
|
||||
previous_state: nil,
|
||||
next_state: 'shipped',
|
||||
name: 'shipment',
|
||||
user_id: order.user_id
|
||||
)
|
||||
|
||||
it "state change" do
|
||||
order = create(:order)
|
||||
order.shipment_state = 'shipped'
|
||||
state_changes = double
|
||||
allow(order).to receive(:state_changes) { state_changes }
|
||||
expect(state_changes).to receive(:create).with(
|
||||
previous_state: nil,
|
||||
next_state: 'shipped',
|
||||
name: 'shipment',
|
||||
user_id: order.user_id
|
||||
)
|
||||
|
||||
order.state_changed('shipment')
|
||||
end
|
||||
|
||||
context "completed order" do
|
||||
before { allow(order).to receive(:completed?) { true } }
|
||||
|
||||
it "updates payment state" do
|
||||
expect(updater).to receive(:update_payment_state)
|
||||
updater.update
|
||||
order.state_changed('shipment')
|
||||
end
|
||||
|
||||
it "updates shipment state" do
|
||||
expect(updater).to receive(:update_shipment_state)
|
||||
updater.update
|
||||
end
|
||||
context "completed order" do
|
||||
before { allow(order).to receive(:completed?) { true } }
|
||||
|
||||
it "updates each shipment" do
|
||||
shipment = build(:shipment)
|
||||
shipments = [shipment]
|
||||
allow(order).to receive_messages shipments: shipments
|
||||
allow(shipments).to receive_messages states: []
|
||||
allow(shipments).to receive_messages ready: []
|
||||
allow(shipments).to receive_messages pending: []
|
||||
allow(shipments).to receive_messages shipped: []
|
||||
it "updates payment state" do
|
||||
expect(updater).to receive(:update_payment_state)
|
||||
updater.update
|
||||
end
|
||||
|
||||
expect(shipment).to receive(:update!).with(order)
|
||||
updater.update
|
||||
end
|
||||
end
|
||||
it "updates shipment state" do
|
||||
expect(updater).to receive(:update_shipment_state)
|
||||
updater.update
|
||||
end
|
||||
|
||||
context "incompleted order" do
|
||||
before { allow(order).to receive_messages completed?: false }
|
||||
it "updates each shipment" do
|
||||
shipment = build(:shipment)
|
||||
shipments = [shipment]
|
||||
allow(order).to receive_messages shipments: shipments
|
||||
allow(shipments).to receive_messages states: []
|
||||
allow(shipments).to receive_messages ready: []
|
||||
allow(shipments).to receive_messages pending: []
|
||||
allow(shipments).to receive_messages shipped: []
|
||||
|
||||
it "doesnt update payment state" do
|
||||
expect(updater).not_to receive(:update_payment_state)
|
||||
updater.update
|
||||
end
|
||||
|
||||
it "doesnt update shipment state" do
|
||||
expect(updater).not_to receive(:update_shipment_state)
|
||||
updater.update
|
||||
end
|
||||
|
||||
it "doesnt update each shipment" do
|
||||
shipment = build(:shipment)
|
||||
shipments = [shipment]
|
||||
allow(order).to receive_messages shipments: shipments
|
||||
allow(shipments).to receive_messages states: []
|
||||
allow(shipments).to receive_messages ready: []
|
||||
allow(shipments).to receive_messages pending: []
|
||||
allow(shipments).to receive_messages shipped: []
|
||||
|
||||
expect(shipment).not_to receive(:update!).with(order)
|
||||
updater.update
|
||||
end
|
||||
end
|
||||
|
||||
it "updates totals twice" do
|
||||
expect(updater).to receive(:update_totals).twice
|
||||
updater.update
|
||||
end
|
||||
|
||||
context "update adjustments" do
|
||||
context "shipments" do
|
||||
it "updates" do
|
||||
expect(updater).to receive(:update_all_adjustments)
|
||||
expect(shipment).to receive(:update!).with(order)
|
||||
updater.update
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "is failed if no valid payments" do
|
||||
allow(order).to receive_message_chain(:payments, :valid, :empty?).and_return(true)
|
||||
context "incompleted order" do
|
||||
before { allow(order).to receive_messages completed?: false }
|
||||
|
||||
updater.update_payment_state
|
||||
expect(order.payment_state).to eq('failed')
|
||||
end
|
||||
it "doesnt update payment state" do
|
||||
expect(updater).not_to receive(:update_payment_state)
|
||||
updater.update
|
||||
end
|
||||
|
||||
context "payment total is greater than order total" do
|
||||
it "is credit_owed" do
|
||||
order.payment_total = 2
|
||||
order.total = 1
|
||||
it "doesnt update shipment state" do
|
||||
expect(updater).not_to receive(:update_shipment_state)
|
||||
updater.update
|
||||
end
|
||||
|
||||
expect {
|
||||
updater.update_payment_state
|
||||
}.to change { order.payment_state }.to 'credit_owed'
|
||||
end
|
||||
end
|
||||
it "doesnt update each shipment" do
|
||||
shipment = build(:shipment)
|
||||
shipments = [shipment]
|
||||
allow(order).to receive_messages shipments: shipments
|
||||
allow(shipments).to receive_messages states: []
|
||||
allow(shipments).to receive_messages ready: []
|
||||
allow(shipments).to receive_messages pending: []
|
||||
allow(shipments).to receive_messages shipped: []
|
||||
|
||||
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'
|
||||
expect(shipment).not_to receive(:update!).with(order)
|
||||
updater.update
|
||||
end
|
||||
end
|
||||
|
||||
context "and is paid" do
|
||||
it "updates totals twice" do
|
||||
expect(updater).to receive(:update_totals).twice
|
||||
updater.update
|
||||
end
|
||||
|
||||
context "update adjustments" do
|
||||
context "shipments" do
|
||||
it "updates" do
|
||||
expect(updater).to receive(:update_all_adjustments)
|
||||
updater.update
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "is failed if no valid payments" do
|
||||
allow(order).to receive_message_chain(:payments, :valid, :empty?).and_return(true)
|
||||
|
||||
updater.update_payment_state
|
||||
expect(order.payment_state).to eq('failed')
|
||||
end
|
||||
|
||||
context "payment total is greater than order total" do
|
||||
it "is credit_owed" do
|
||||
order.payment_total = 30
|
||||
order.total = 30
|
||||
allow(order).to receive_message_chain(:payments, :valid, :empty?).and_return(false)
|
||||
allow(order).to receive_message_chain(:payments, :completed, :empty?).and_return(false)
|
||||
order.payment_total = 2
|
||||
order.total = 1
|
||||
|
||||
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
|
||||
allow(order).to receive_message_chain(:payments, :valid, :empty?).and_return(false)
|
||||
allow(order).to receive_message_chain(:payments, :completed, :empty?).and_return(false)
|
||||
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 'void'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the set payment_state does not match the last payment_state' do
|
||||
before { order.payment_state = 'previous_to_paid' }
|
||||
|
||||
context 'and the order is being updated' do
|
||||
before { allow(order).to receive(:persisted?) { true } }
|
||||
|
||||
it 'creates a new state_change for the order' do
|
||||
expect { updater.update_payment_state }
|
||||
.to change { order.state_changes.size }.by(1)
|
||||
}.to change { order.payment_state }.to 'balance_due'
|
||||
end
|
||||
end
|
||||
|
||||
context 'and the order is being created' do
|
||||
before { allow(order).to receive(:persisted?) { false } }
|
||||
context "order total equals payment total" do
|
||||
it "is paid" do
|
||||
order.payment_total = 30
|
||||
order.total = 30
|
||||
|
||||
it 'creates a new state_change for the order' do
|
||||
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
|
||||
allow(order).to receive_message_chain(:payments, :valid, :empty?).and_return(false)
|
||||
allow(order).to receive_message_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
|
||||
allow(order).to receive_message_chain(:payments, :valid, :empty?).and_return(false)
|
||||
allow(order).to receive_message_chain(:payments, :completed, :empty?).and_return(false)
|
||||
expect {
|
||||
updater.update_payment_state
|
||||
}.to change { order.payment_state }.to 'void'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the set payment_state does not match the last payment_state' do
|
||||
before { order.payment_state = 'previous_to_paid' }
|
||||
|
||||
context 'and the order is being updated' do
|
||||
before { allow(order).to receive(:persisted?) { true } }
|
||||
|
||||
it 'creates a new state_change for the order' do
|
||||
expect { updater.update_payment_state }
|
||||
.to change { order.state_changes.size }.by(1)
|
||||
end
|
||||
end
|
||||
|
||||
context 'and the order is being created' do
|
||||
before { allow(order).to receive(:persisted?) { false } }
|
||||
|
||||
it 'creates a new state_change for the order' do
|
||||
expect { updater.update_payment_state }
|
||||
.not_to change { order.state_changes.size }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the set payment_state matches the last payment_state' do
|
||||
before { order.payment_state = 'paid' }
|
||||
|
||||
it 'does not create any state_change' do
|
||||
expect { updater.update_payment_state }
|
||||
.not_to change { order.state_changes.size }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the set payment_state matches the last payment_state' do
|
||||
before { order.payment_state = 'paid' }
|
||||
context '#before_save_hook' do
|
||||
let(:distributor) { build(:distributor_enterprise) }
|
||||
let(:shipment) { create(:shipment_with, :shipping_method, shipping_method: shipping_method) }
|
||||
|
||||
it 'does not create any state_change' do
|
||||
expect { updater.update_payment_state }
|
||||
.not_to change { order.state_changes.size }
|
||||
end
|
||||
end
|
||||
|
||||
context '#before_save_hook' do
|
||||
let(:distributor) { build(:distributor_enterprise) }
|
||||
let(:shipment) { create(:shipment_with, :shipping_method, shipping_method: shipping_method) }
|
||||
|
||||
before do
|
||||
order.distributor = distributor
|
||||
order.shipments = [shipment]
|
||||
end
|
||||
|
||||
context 'when shipping method is pickup' do
|
||||
let(:shipping_method) { create(:shipping_method_with, :pickup) }
|
||||
let(:address) { build(:address, firstname: 'joe') }
|
||||
before { distributor.address = address }
|
||||
|
||||
it "populates the shipping address from distributor" do
|
||||
updater.before_save_hook
|
||||
expect(order.ship_address.address1).to eq(distributor.address.address1)
|
||||
before do
|
||||
order.distributor = distributor
|
||||
order.shipments = [shipment]
|
||||
end
|
||||
end
|
||||
|
||||
context 'when shipping_method is delivery' do
|
||||
let(:shipping_method) { create(:shipping_method_with, :delivery) }
|
||||
let(:address) { build(:address, firstname: 'will') }
|
||||
before { order.ship_address = address }
|
||||
context 'when shipping method is pickup' do
|
||||
let(:shipping_method) { create(:shipping_method_with, :pickup) }
|
||||
let(:address) { build(:address, firstname: 'joe') }
|
||||
before { distributor.address = address }
|
||||
|
||||
it "does not populate the shipping address from distributor" do
|
||||
updater.before_save_hook
|
||||
expect(order.ship_address.firstname).to eq("will")
|
||||
it "populates the shipping address from distributor" do
|
||||
updater.before_save_hook
|
||||
expect(order.ship_address.address1).to eq(distributor.address.address1)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when shipping_method is delivery' do
|
||||
let(:shipping_method) { create(:shipping_method_with, :delivery) }
|
||||
let(:address) { build(:address, firstname: 'will') }
|
||||
before { order.ship_address = address }
|
||||
|
||||
it "does not populate the shipping address from distributor" do
|
||||
updater.before_save_hook
|
||||
expect(order.ship_address.firstname).to eq("will")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user