Skip to content

Instantly share code, notes, and snippets.

@simmsy
Last active August 29, 2015 13:57
Show Gist options
  • Save simmsy/9684227 to your computer and use it in GitHub Desktop.
Save simmsy/9684227 to your computer and use it in GitHub Desktop.
# The fundamantal design opinion is that a Stock Return has many Returned Items
# Each Returned Item effectively has one of 3 actions associated with it return, exchange OR replace
# Any of these action can involve a refund, although the most common is that a return involves a refund
# You may wish to refund a replacement Or exchange to maintain customer relations
#
# Once all Returned Items and their actions have been set then you can commence to attempt to process the Stock Return
# Processing the Stock Return will automate the Order Adjustments, Addiitonal Shipments and any Refunds / Payments
# It should be exstensible so that developers can easily implement their own behaviour here
#
# It could be that a developer can extend this to Create New Orders instead of Additional Shipments under certain scenarios:
# When the total of the exchanged items exceed the balance on the Order, it might be preferable to require a new payment, hence new Order
class StockReturn
# return_cost
# handling_cost
# timestamps
has_many :returned_items
has_many :exchange_items
before_transistion_to :complete, :handle_return
# Validate processable?
def processable?
Spree::StockReturnHandler.factory(self).processable?
end
def handle_return
Spree::StockReturnHandler.factory(self).process!
end
end
# A Returned Item has 3 actions: return, replace or exchange
# You can refund (using refund_amount not null and > 0) with ANY of the actions above
#
# Attributes:
# - reason: provided by customer (wrong_size, not_suitable, not_as_described, arrived_late, other, etc)
# - reason_other : string
# - refund_amount: allow null, null is unknown and therefore unprocessable, must be set to 0 if no refund provided
# NOTE: No qty for line item, each one has a separate record
#
# Potentially:
# - condition: provided by receiver (faulty, damaged, good)
# - restock: boolean (null is unknown and therefore unprocessable)
class ReturnedItem
enum action: [:return, :replace, :exchange]
enum reason: REASON_CODES
belongs_to :stock_return
belongs_to :line_item
# If certain Reason Codes provided then we can auto set refund amount
before_create :auto_set_refund_amount
def refund?
refund_amount.present? && refund_amount > 0
end
end
class ExchangeItem
# price (defaults to line_item current price but if set here is overriden)
belongs_to :stock_return
belongs_to :line_item
end
class StockReturnHandler
def initialize(stock_return)
@stock_return
end
def processable?
# These methods add errors to the Stock Return object
refund_due_within_processable_boundary?
exchange_items_shipable?
replacement_items_shipable?
@stock_return.valid?
end
def perform
return false unless processable?
adjust_order_for_return_cost
adjust_order_for_handling_fee
create_shipments_for_exchanged_and_replacement_items
process_balance #(refund or charge additional)
true
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment