app/models/orders/order.rb in artfully_ose-1.0.0.rc4 vs app/models/orders/order.rb in artfully_ose-1.1.0.rc1
- old
+ new
@@ -1,41 +1,87 @@
#Subclasses (and their type) should speak to the *location* or *nature* of the order, not the contents of the items
# WebOrder, BoxOfficeOrder for example. NOT DonationOrder, since orders may contain multiple different item types
class Order < ActiveRecord::Base
include ActionView::Helpers::NumberHelper
include ActionView::Helpers::TextHelper
- include ArtfullyOseHelper
include Ext::Integrations::Order
+ include OhNoes::Destroy
+ include ArtfullyOseHelper
#This is a lambda used to by the items to calculate their net
attr_accessor :per_item_processing_charge
+ attr_accessible :person_id, :organization_id, :person, :organization, :details
+
belongs_to :person
belongs_to :organization
+ belongs_to :import
belongs_to :parent, :class_name => "Order", :foreign_key => "parent_id"
+ belongs_to :gateway_transaction, :primary_key => :transaction_id, :foreign_key => :transaction_id
has_many :children, :class_name => "Order", :foreign_key => "parent_id"
- has_many :items
- has_many :actions, :foreign_key => "subject_id"
+ has_many :items, :dependent => :destroy
+ has_many :actions, :foreign_key => "subject_id", :dependent => :destroy
attr_accessor :skip_actions
set_watch_for :created_at, :local_to => :organization
set_watch_for :created_at, :local_to => :self, :as => :admins
validates_presence_of :person_id
validates_presence_of :organization_id
+ # Both of these are handle_asynchronously
after_create :create_purchase_action, :unless => :skip_actions
after_create :create_donation_actions, :unless => :skip_actions
+ after_create :sell_tickets
+
default_scope :order => 'orders.created_at DESC'
scope :before, lambda { |time| where("orders.created_at < ?", time) }
scope :after, lambda { |time| where("orders.created_at > ?", time) }
scope :imported, where("fa_id IS NOT NULL")
scope :not_imported, where("fa_id IS NULL")
+ scope :csv_imported, where("import_id IS NOT NULL")
+ scope :csv_not_imported, where("import_id IS NULL")
scope :artfully, where("transaction_id IS NOT NULL")
+ searchable do
+ text :details, :id, :type, :location, :transaction_id, :payment_method, :special_instructions
+
+ [:first_name, :last_name, :email].each do |person_field|
+ text person_field do
+ person.send(person_field) unless person.nil?
+ end
+ end
+
+ text :organization_id do
+ organization.id
+ end
+
+ text :organization_name do
+ organization.name
+ end
+
+ text :event_name do
+ items.map{ |item| item.show.event.name unless item.show.nil? }
+ end
+
+ string :details, :id, :type, :location, :transaction_id, :payment_method, :special_instructions
+ string :organization_id do
+ organization.id
+ end
+
+ string :organization_name do
+ organization.name
+ end
+
+ string :event_name, :multiple => true do
+ items.map{ |item| item.show.event.name unless item.show.nil? }
+ end
+ end
+ include Ext::DelayedIndexing
+
def self.in_range(start, stop, organization_id = nil)
query = after(start).before(stop).includes(:items, :person, :organization).order("created_at DESC")
if organization_id.present?
query.where('organization_id = ?', organization_id)
else
@@ -46,27 +92,31 @@
def artfully?
!transaction_id.nil?
end
def location
+ self.class.location
+ end
+
+ def self.location
""
end
def total
all_items.inject(0) {|sum, item| sum + item.total_price.to_i }
end
def nongift_amount
all_items.inject(0) {|sum, item| sum + item.nongift_amount.to_i }
end
-
- def tickets
- items.select(&:ticket?)
+
+ def destroyable?
+ ( (type.eql? "ApplicationOrder") || (type.eql? "ImportedOrder") ) && !is_fafs? && !artfully? && has_single_donation?
end
-
- def donations
- items.select(&:donation?)
+
+ def editable?
+ ( (type.eql? "ApplicationOrder") || (type.eql? "ImportedOrder") ) && !is_fafs? && !artfully? && has_single_donation?
end
def for_organization(org)
self.organization = org
end
@@ -74,16 +124,16 @@
def <<(products)
self.items << Array.wrap(products).collect { |product| Item.for(product, @per_item_processing_charge) }
end
def payment
- AthenaPayment.new(:transaction_id => transaction_id)
+ CreditCardPayment.new(:transaction_id => transaction_id)
end
- def record_exchange!
- items.each do |item|
- item.to_exchange!
+ def record_exchange!(exchanged_items)
+ items.each_with_index do |item, index|
+ item.to_exchange! exchanged_items[index]
end
end
def all_items
merge_and_sort_items
@@ -91,26 +141,45 @@
def all_tickets
all_items.select(&:ticket?)
end
+ #TODO: Undupe these methods
+ def tickets
+ items.select(&:ticket?)
+ end
+
def all_donations
all_items.select(&:donation?)
end
+ def donations
+ items.select(&:donation?)
+ end
+ #End dupes
+
+ def has_single_donation?
+ (donations.size == 1) && tickets.empty?
+ end
+
def settleable_donations
all_donations.reject(&:modified?)
end
def refundable_items
+ return [] unless Payment.create(payment_method).refundable?
items.select(&:refundable?)
end
def exchangeable_items
items.select(&:exchangeable?)
end
+ def returnable_items
+ items.select { |i| i.returnable? and i.comped? and not i.refundable? }
+ end
+
def num_tickets
all_tickets.size
end
def has_ticket?
@@ -120,15 +189,26 @@
def has_donation?
items.select(&:donation?).present?
end
def sum_donations
- all_donations.collect{|item| item.price.to_i}.sum
+ all_donations.collect{|item| item.total_price.to_i}.sum
end
+ #
+ # Will return an array of all discount codes on all items on this order
+ #
+ def discounts_used
+ items.map{|i| i.discount.try(:code)}.reject(&:blank?).uniq
+ end
+
def ticket_details
- pluralize(num_tickets, "ticket") + " to " + all_tickets.first.show.event.name
+ discount_string = ""
+ unless discounts_used.empty?
+ discount_string = ", used #{'discount'.pluralize(discounts_used.length)} " + discounts_used.join(",")
+ end
+ Ticket.to_sentence(self.tickets.map(&:product)) + discount_string
end
def to_comp!
items.each do |item|
item.to_comp!
@@ -139,68 +219,101 @@
!fa_id.nil?
end
def donation_details
if is_fafs?
- o = Organization.find(organization_id)
- "#{number_as_cents sum_donations} donation via Fractured Atlas for the benefit of #{o.fiscally_sponsored_project.name}"
+ "#{number_as_cents sum_donations} donation made through Fractured Atlas"
else
"#{number_as_cents sum_donations} donation"
end
end
-
- def returnable_items
- items.select { |i| i.returnable? and not i.refundable? }
- end
def ticket_summary
summary = TicketSummary.new
items.select(&:ticket?).each do |item|
summary << item.product
end
summary
end
def credit?
- payment_method.eql? 'Credit card'
+ payment_method.eql? CreditCardPayment.payment_method
end
+
+ def cash?
+ payment_method.eql? CashPayment.payment_method
+ end
+
+ def original_order
+ if self.parent.nil?
+ return self
+ else
+ return self.parent.original_order
+ end
+ end
+
+ #
+ # If this order has no transaction_id, run up the parent chain until we hit one
+ # This is needed for exchanges that ultimately need to be refunded
+ #
+ def transaction_id
+ read_attribute(:transaction_id) || self.parent.try(:transaction_id)
+ end
+ def sell_tickets
+ all_tickets.each do |item|
+ item.product.sell_to(self.person, self.created_at)
+ end
+ end
+
def time_zone
"Eastern Time (US & Canada)"
end
- private
+ def contact_email
+ items.try(:first).try(:show).try(:event).try(:contact_email)
+ end
- #this used to do more. Now it only does this
- def merge_and_sort_items
- items
+ def create_donation_actions
+ items.select(&:donation?).collect do |item|
+ action = GiveAction.new
+ action.person = person
+ action.subject = self
+ action.organization_id = organization.id
+ action.details = donation_details
+ action.occurred_at = created_at
+ action.subtype = "Monetary"
+ action.save!
+ action
end
+ end
+ handle_asynchronously :create_donation_actions
- def create_purchase_action
- unless all_tickets.empty?
- action = GetAction.new
- action.person = person
- action.subject = self
- action.organization_id = organization.id
- action.details = ticket_details
- action.occurred_at = created_at
- action.subtype = "Purchase"
+ def create_purchase_action
+ unless all_tickets.empty?
+ action = purchase_action_class.new
+ action.person = person
+ action.subject = self
+ action.organization = organization
+ action.details = ticket_details
+ action.occurred_at = created_at
- action.save!
- action
- end
+ #Weird, but Rails can't initialize these so the subtype is hardcoded in the model
+ action.subtype = action.subtype
+ action.import = self.import if self.import
+ action.save!
+ action
end
+ end
+ handle_asynchronously :create_purchase_action
- def create_donation_actions
- items.select(&:donation?).collect do |item|
- action = GiveAction.new
- action.person = person
- action.subject = self
- action.organization_id = organization.id
- action.details = donation_details
- action.occurred_at = created_at
- action.subtype = "Donation"
- action.save!
- action
- end
+ def purchase_action_class
+ GetAction
+ end
+
+ private
+
+ #this used to do more. Now it only does this
+ def merge_and_sort_items
+ items
end
end