module Comable class Shipment < ActiveRecord::Base include Comable::Ransackable belongs_to :order, class_name: Comable::Order.name, inverse_of: :shipments belongs_to :shipment_method, class_name: Comable::ShipmentMethod.name belongs_to :stock_location, class_name: Comable::StockLocation.name has_many :shipment_items, class_name: Comable::ShipmentItem.name, inverse_of: :shipment before_validation :copy_attributes_from_shipment_method, unless: :order_completed? validates :order, presence: true validates :shipment_method, presence: true, if: -> { stated?(:pending) && Comable::ShipmentMethod.activated.exists? } validates :fee, presence: true, numericality: { greater_than_or_equal_to: 0 } validates :tracking_number, length: { maximum: 255 } ransack_options ransackable_attributes: { except: [:order_id, :shipment_method_id] } # The #state attribute assigns the following values: # # pending when Order is not able to ship (default) # ready when Order is able to ship # completed when Order is already shipped # canceled when Order is canceled # resumed when Order is resumed from the "canceled" state state_machine initial: :pending do state :pending state :ready state :completed state :canceled state :resumed event :next_state do transition :pending => :ready transition :ready => :completed end event :ship do transition :ready => :completed end event :cancel do transition [:completed, :resumed] => :canceled end event :resume do transition :canceled => :resumed end before_transition to: :ready, do: -> (s) { s.ready! } before_transition to: :completed, do: -> (s) { s.complete! } end class << self def state_names state_machine.states.keys end end def stated?(target_state) target_state_index = self.class.state_names.index(target_state.to_sym) current_state_index = self.class.state_names.index(state_name) target_state_index < current_state_index end def completed? completed_at? end def ready! shipment_items.each(&:ready!) end def complete! touch :completed_at end def restock! shipment_items.each(&:restock!) end def unstock! shipment_items.each(&:unstock!) end def can_ship? ready? && order.paid? && order.completed? end def name shipment_method.try(:name) || Comable.t(:normal_shipment) end def current_fee shipment_method.try(:fee) || 0 end private def order_completed? order.completed? end def copy_attributes_from_shipment_method self.attributes = { fee: current_fee } end end end