Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ## Hold.rb
- # require 'hold_states'
- require 'hold_commands'
- class Hold < ActiveRecord::Base
- acts_as_tree
- include AlterEgo
- state :active, :default => true do
- handle(:can_cancel?){|user_or_code|
- p("should be user_or_code but is context: #{user_or_code}")
- is_owner?(user_or_code) || root.is_owner?(user_or_code)
- }
- handle(:can_edit?){|user_or_code| is_owner?(user_or_code) || root.is_owner?(user_or_code) }
- handle(:state_text){ "Waiting for #{email_address} to purchase" }
- handle(:timer_amount){
- d = (expires_at.utc - Time.now.utc).to_i
- [d/3600, d%3600/60, d%3600%60]
- }
- transition(:to => :expired, :on => :expire!, :if => Proc.new{|r| r.expires_at < Time.now && !r.new_record?})
- transition(:to => :deleted, :on => :delete!)
- transition(:to => :cancelled, :on => :cancel!)
- transition(:to => :purchased, :on => :purchase!)
- end
- # include HoldStates # Contains all state based behaviors
- include HoldCommands # Contains all of the commands that can be executed
- MAX_TIMER_AMOUNT = [4.hours, 0.minutes, 0.seconds]
- attr_accessor :message, :target, :offers_for_transfer, :split_email
- belongs_to :user
- belongs_to :offerset
- has_many :held_tickets
- named_scope :active, :conditions => "holds.state='active'"
- before_validation_on_create :generate_invite_code, :set_timer
- before_validation Proc.new{|r| r.write_attribute(:state, r.state.to_s) }
- after_create Proc.new{|r| HoldMailer.deliver_new_seat_pause(r) if r == r.root}
- validates_presence_of :expires_at, :offerset_id
- validates_presence_of :email_address, :unless => Proc.new{|r| r.user}
- validates_presence_of :invite_code, :unless => Proc.new{|r| r.user}
- validate_on_create :prior_hold_does_not_exist
- validate :offers_are_valid
- class << self
- def assign_owner_by_invite_codes(user, invite_codes)
- user.holds << Hold.find(:all, :conditions => {:user_id => nil, :invite_code => invite_codes})
- user.save
- end
- def expire_holds!
- all(:conditions => ["state='active' AND expires_at < ?", Time.now.utc]).each do |h|
- puts("EXPIRE_HOLDS:: expiring hold #{h.id}")
- end
- end
- def for_user_and_offerset(user, offerset)
- return nil unless user && offerset
- user.holds.active.find(:first, :conditions => {:offerset_id => offerset.id})
- end
- end
- def auto_start_split_wizard?
- read_attribute('hold_type') == 1 && hold_type == 'seat_pause'
- end
- def belongs_to_essential?
- ignore_nil{user.essential?}
- end
- def child_of_a?(hold_type)
- ignore_nil{parent.hold_type} == hold_type
- end
- def descendants
- children.map(&:descendants).flatten + children
- end
- def email_address
- read_attribute(:email_address) || ignore_nil{user.email}
- end
- def expires_at=(time)
- # we cant allow the specified time to go past the offerset deadline
- if offerset && Time.now.utc >= offerset.expires_at.utc
- raise HoldError.new("Sorry, we are unable to give you more time for this hold.")
- elsif offerset && time.utc >= offerset.expires_at.utc
- time = offerset.expires_at.utc
- end
- # if this is a new record, we simply want to set the expires at so the save hits it
- if new_record?
- write_attribute(:expires_at, time)
- else
- Hold.connection.execute("UPDATE holds SET expires_at='#{time.utc.to_s(:db)}' WHERE id IN (#{group.map(&:id)*', '})")
- end
- end
- def group
- ([self, root] + root.descendants).uniq.compact
- end
- def historic_quantity
- held_tickets.inject(0){|total, ticket| total += ticket.historic_quantity_held}
- end
- def historic_quantity_for_group
- group.inject(0){|total, hold| total += hold.historic_quantity_held}
- end
- def hold_type
- if children(true).active.empty?
- 'seat_pause'
- elsif !children(true).active.empty? && quantity_held == 0
- 'transfer'
- elsif !children(true).active.empty? && quantity_held > 0
- 'group'
- end
- end
- def is_owner?(user_or_code)
- Array(user_or_code).include?(user) || Array(user_or_code).include?(invite_code)
- end
- def offers
- held_tickets.map(&:offer)
- end
- def offers=(offer_hash)
- Hold.transaction do
- held_tickets.delete_all
- offer_hash.each_pair do |offer_id, quantity|
- next if quantity.blank?
- offer = Offer.find(offer_id)
- held_tickets.build(:offer_id => offer_id.to_i, :quantity => quantity.to_i, :our_price => offer.our_price, :service_fee => offer.service_fee)
- end
- unless held_tickets.all(&:valid?)
- errors.add_base('Not all tickets could be saved')
- raise ActiveRecord::Rollback.new('Not all tickets could be saved')
- end
- end
- errors.empty?
- end
- def offers_for_transfer=(offers_hash)
- @offers_for_transfer = offers_hash.reject{|oid, qty| qty.blank?}
- end
- def on_hold_until
- expires_at.strftime("%A, %B %d, %I:%M%p")
- end
- def owner_name
- ignore_nil{user.name} || email_address
- end
- def part_of_group?
- return (hold_type == 'group' || read_attribute(:hold_type) == 1) if self == root
- ancestors.any?{|a| (a.hold_type == 'group' || a.read_attribute(:hold_type) == 1)}
- end
- def pass_back_tickets
- run_commands(ReturnHeldTicketsToParent)
- end
- def purchase
- return nil unless purchased?
- purchased_tickets.first.purchase
- end
- def purchased_tickets
- held_tickets.map(&:claim).compact
- end
- def quantity_held
- held_tickets.inject(0){|total, ticket| total += ticket.quantity_held}
- end
- def quantity_held_for_group
- group.inject(0){|total, hold| total += hold.quantity_held}
- end
- def split(params)
- Hold.transaction do
- self.offers_for_transfer = params[:offers]
- self.message = params[:message]
- self.split_email = params[:email_address]
- run_commands(SplitHold, TransferTickets, DeliverSplitRecipient)
- raise ActiveRecord::Rollback.new('There were errors while trying to split this hold.') unless errors.empty?
- end
- errors.empty?
- end
- def transfer_tickets(target, offers)
- Hold.transaction do
- self.target, self.offers_for_transfer = target, offers
- run_commands(TransferTickets)
- raise ActiveRecord::Rollback.new('There were errors while trying to transfer tickets') unless errors.empty?
- end
- end
- private
- def after_initialize
- expire!
- end
- def generate_invite_code
- return if user || invite_code
- self.invite_code = Digest::SHA1.hexdigest("--#{Time.now.utc.to_s}--#{email_address}--")
- end
- def offers_are_valid
- errors.add_to_base('All offers must come from the same offerset.') and return unless offers.empty? || Offer::all_offers_are_for_the_same_offerset?(offers)
- errors.add_to_base('All offers must be in the same branch.') and return unless offers.empty? || Offer::all_offers_are_in_the_same_offer_branch_above_parent?(offers)
- errors.add_to_base('This date/time has expired, please try another.') and return if offerset && offerset.expired?
- errors.add_to_base('This date/time has been cancelled, please try another.') and return if offerset && offerset.cancelled?
- errors.add_to_base('This date/time has been closed, please try another.') and return if offerset && offerset.closed?
- end
- def prior_hold_does_not_exist
- errors.add_to_base("You already have a hold for this event.") if Hold.for_user_and_offerset(user, offerset)
- end
- def set_timer
- self.expires_at = (ignore_nil{root.expires_at} || (Time.now+MAX_TIMER_AMOUNT.sum))
- end
- end
- ## Specs outlining the issue
- it "prove alter ego is sucking atm" do
- @h = Hold.new(:invite_code => 'owner')
- @h.is_owner?('owner').should be_true
- @h.can_cancel?('owner').should be_true
- end
Add Comment
Please, Sign In to add comment