Skip to content

Instantly share code, notes, and snippets.

@braidn
Created December 12, 2014 01:43
Show Gist options
  • Save braidn/fa6e4d79784b73d7b608 to your computer and use it in GitHub Desktop.
Save braidn/fa6e4d79784b73d7b608 to your computer and use it in GitHub Desktop.
module Spree
Order.instance_eval do
def find_by_number(number)
order = complete.where(number:number).take
order ||= where(number:number).take
end
def find_by_number!(number)
find_by_number(number)
end
end
Order.class_eval do
cattr_accessor :env
scope :line_item_count_gt, ->(count) {
select("#{Spree::Order.table_name}.*").
joins(:line_items).
group("#{Spree::Order.table_name}.id").
having("count(#{Spree::LineItem.table_name}.id) > ?", count)
}
scope :has_promotion, ->(id) {
joins(:adjustments).where("#{Spree::Adjustment.table_name}.originator_type = 'Spree::PromotionAction' AND #{Spree::Adjustment.table_name}.originator_id IN (?)", Spree::Promotion.find(id).promotion_actions.map(&:id))
}
after_save :set_user_id_on_addresses
def self.define_state_machine!
self.checkout_steps = {}
self.next_event_transitions = []
self.previous_states = [:cart]
self.removed_transitions = []
# Build the checkout flow using the checkout_flow defined either
# within the Order class, or a decorator for that class.
#
# This method may be called multiple times depending on if the
# checkout_flow is re-defined in a decorator or not.
instance_eval(&checkout_flow)
klass = self
# To avoid a ton of warnings when the state machine is re-defined
StateMachine::Machine.ignore_method_conflicts = true
# To avoid multiple occurrences of the same transition being defined
# On first definition, state_machines will not be defined
state_machines.clear if respond_to?(:state_machines)
state_machine :state, :initial => :cart, :use_transactions => false, :action => :save_state do
klass.next_event_transitions.each { |t| transition(t.merge(:on => :next)) }
# Persist the state on the order
after_transition do |order, transition|
order.state = order.state
order.state_changes.create(
previous_state: transition.from,
next_state: transition.to,
name: 'order',
user_id: order.user_id
)
order.save
end
event :cancel do
transition :to => :canceled, :if => :allow_cancel?
end
event :return do
transition :to => :returned, :from => :awaiting_return, :unless => :awaiting_returns?
end
event :resume do
transition :to => :resumed, :from => :canceled, :if => :canceled?
end
event :authorize_return do
transition :to => :awaiting_return
end
before_transition :from => :cart, :do => :ensure_line_items_present
if states[:address]
before_transition :from => :address, :do => :create_tax_charge!
end
if states[:delivery]
before_transition :to => :delivery, :do => :create_proposed_shipments
before_transition :to => :delivery, :do => :ensure_available_shipping_rates
end
after_transition :to => :complete, :do => :finalize!
after_transition :to => :resumed, :do => :after_resume
after_transition :to => :canceled, :do => :after_cancel
# ADD CUSTOM TRANSITIONS HERE
end
end
alias_method :save_state, :save
def generate_order_number
if self.number.blank?
next_id = ActiveRecord::Base.connection.select_value("select nextval('spree_orders_id_seq')")
self.number = "R#{next_id.to_s.rjust(10, '0')}"
end
self.number
end
def tax_total
tax_adjustment.try(:amount) || 0
end
def tax_adjustment
adjustments.find_by(originator_type:'Spree::TaxRate')
end
# Required for Promotion_Tax.rb Calculator
def promotions_total
# Find the best promotion to calculate from
active_promotion = adjustments.promotion.max_by {|promo| promo.amount.abs}
active_promotion.try(:amount).to_f
end
def set_user_id_on_addresses
return if user.nil?
[ ship_address, bill_address ].each do |address|
next if address.nil?
next unless address.save_for_later
if user.addresses.any?
user.addresses.each do |a|
next if address.same? a
end
end
address.try :update_attribute, :user_id, user.id
end
end
def international?
shipping_address.country.id != 49 if shipping_address.present?
end
def process_payments!
if pending_payments.any?
pending_payments.each do |payment|
break if payment_total >= total
payment.process!
if payment.completed?
self.payment_total += payment.amount
end
end
end
rescue Core::GatewayError => e
result = !!Spree::Config[:allow_checkout_on_gateway_error]
errors.add(:base, e.message) and return result
end
def is_risky?
self.payments.where(%{
(avs_response IS NOT NULL and avs_response != '' and avs_response != 'D' and avs_response != 'M' and avs_response != 'Y' and avs_response != 'X') or
(cvv_response_code IS NOT NULL and cvv_response_code != 'M') or
state = 'failed'
}.squish!).uniq.count > 0
end
def push_to_hub
return unless self.line_items.count > 0
return if self.shipment_state == 'shipped'
Spree::Hub::Client.push(serialized_payload)
end
def serialized_payload
ActiveModel::ArraySerializer.new(
[self],
each_serializer: self.class.hub_serializer.constantize,
root: self.completed_at.present? ? self.class.json_root_name : 'carts'
).to_json
end
def refresh_line_item_prices!
if completed_at.nil?
refreshed_line_items = line_items.select{|li| li.price != li.variant.price }
if refreshed_line_items.present?
ActiveRecord::Base.transaction do
for li in refreshed_line_items
li.old_price = li.price
li.update_columns price: li.variant.price, updated_at: Time.current
end
create_tax_charge!
update!
end
return true
end
end
false
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment