Class: Pass
- Inherits:
-
ActiveRecord::Base
- Object
- ActiveRecord::Base
- Pass
- Includes:
- Extendable
- Defined in:
- app/models/pass.rb
Constant Summary collapse
- EXPIRED_ERROR =
"Sorry! This pass has expired."
- OUT_OF_TICKETS =
"Sorry! There are no tickets remaning on this pass."
- OVER_EVENT_LIMIT =
"Sorry! This pass has already been redeemed for this event."
- EVENT_NOT_ELIGIBLE =
"This pass is not eligible for some of the events in your cart."
- SHOW_NOT_ELIGIBLE =
"This pass is not eligible for some of the shows in your cart."
- TICKET_TYPE_NOT_ELIGIBLE =
"This pass is not eligible for some of the ticket types in your cart"
- ORG_ERROR =
"Sorry! This pass is not eligible for some of the tickets in your cart"
Class Method Summary collapse
Instance Method Summary collapse
- #adjust_ends_at ⇒ Object
- #alive? ⇒ Boolean
- #applies_to?(thing) ⇒ Boolean
- #apply_pass_to_cart(cart) ⇒ Object
- #cart_price ⇒ Object
- #exchangeable? ⇒ Boolean
- #expire! ⇒ Object
- #expired? ⇒ Boolean
- #realized_fee ⇒ Object
- #refundable? ⇒ Boolean
- #returnable? ⇒ Boolean
-
#tickets_purchased ⇒ Object
We intentionally go to the DB here to avoid race conditions when applying a pass to the cart.
- #tickets_remaining_for(event) ⇒ Object
Methods included from Extendable
Class Method Details
.for(pass_type) ⇒ Object
23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'app/models/pass.rb', line 23 def self.for(pass_type) new.tap do |pass| pass.pass_type = pass_type pass.organization = pass_type.organization pass.price = pass_type.price pass.sold_price = pass.price pass.tickets_allowed = pass_type.tickets_allowed pass.pass_code = new_pass_code pass.starts_at = pass_type.starts_at pass.ends_at = pass_type.ends_at end end |
.new_pass_code(size = 8) ⇒ Object
83 84 85 86 87 |
# File 'app/models/pass.rb', line 83 def self.new_pass_code(size=8) # Avoid confusable characters like 1/L/I and 0/O charset = %w{ 2 3 4 6 7 9 A C D E F G H J K M N P Q R T V W X Y Z} (0...size).map{ charset.to_a[rand(charset.size)] }.join end |
.to_sentence(passes) ⇒ Object
93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'app/models/pass.rb', line 93 def self.to_sentence(passes) if passes.any? pass_types = passes.collect(&:pass_type).uniq if pass_types.length > 1 "multiple passes" else ActionController::Base.helpers.pluralize(passes.length, "#{passes.first.pass_type.passerize}") end else "No passes" end end |
Instance Method Details
#adjust_ends_at ⇒ Object
36 37 38 |
# File 'app/models/pass.rb', line 36 def adjust_ends_at self.ends_at = self.ends_at.end_of_day unless self.ends_at.blank? end |
#alive? ⇒ Boolean
63 64 65 |
# File 'app/models/pass.rb', line 63 def alive? (tickets_allowed > tickets_purchased) && (starts_at < DateTime.now) && (ends_at > DateTime.now) end |
#applies_to?(thing) ⇒ Boolean
89 90 91 |
# File 'app/models/pass.rb', line 89 def applies_to?(thing) thing.applies_to_pass? self end |
#apply_pass_to_cart(cart) ⇒ Object
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'app/models/pass.rb', line 117 def apply_pass_to_cart(cart) Rails.logger.debug ("PASSES Applying pass [#{self.id}] to cart [#{cart.id}]") cart.prepare_for_pass! #the number of tickets remining for this pass. We go straight to the DB here #to avoid a race condition on pass.tickets_remaining tickets_remaining_on_pass = self.tickets_allowed - tickets_purchased Rails.logger.debug ("PASSES [#{tickets_remaining_on_pass}] tickets remaining on this pass") self.errors.add(:base, EXPIRED_ERROR) and return if self.expired? self.errors.add(:base, OUT_OF_TICKETS) and return if tickets_remaining_on_pass < 1 #The list of tickets w'eve applied this pass too tickets_applied = [] #The list of tickets we rejected for being over the limit tickets_rejected = [] over_event_limit = false pass_errors = Set.new transaction do cart.applied_pass = self cart.tickets.each do |ticket| (pass_errors << EVENT_NOT_ELIGIBLE and next) unless self.applies_to? (ticket.show.event) (pass_errors << SHOW_NOT_ELIGIBLE and next) unless self.applies_to? (ticket.show) (pass_errors << TICKET_TYPE_NOT_ELIGIBLE and next) unless self.applies_to? (ticket.ticket_type) (pass_errors << ORG_ERROR and next) unless (self.organization == ticket.organization) event = ticket.show.event tickets_remaining_for_this_event = tickets_remaining_for(event) Rails.logger.debug ("PASSES [#{tickets_remaining_for_this_event}] tickets remaining to event [#{event.id}]") over_event_limit = true if tickets_remaining_for_this_event == 0 tickets_remaining = [tickets_remaining_on_pass, tickets_remaining_for_this_event].min Rails.logger.debug ("PASSES [#{tickets_remaining}] tickets remaining after considering pass and event") if tickets_remaining > 0 Rails.logger.debug ("PASSES adding pass [#{self.id}] to ticket [#{ticket.id}]") ticket.pass = self ticket.cart_price = 0 ticket.save tickets_applied << ticket tickets_remaining_on_pass = tickets_remaining_on_pass - 1 Rails.logger.debug ("PASSES Now only [#{tickets_remaining_on_pass}] tickets remaining on this pass") else Rails.logger.debug ("PASSES rejecting ticket [#{ticket.id}]") tickets_rejected << tickets end end if tickets_rejected.length > 0 str = "" if tickets_applied.length == 0 str += "There are no tickets" else str += "Only #{ActionController::Base.helpers.pluralize(tickets_applied.length, 'ticket')}" str += tickets_applied.length > 1 ? " were" : " was" end str += " remaining on this pass" str += " for this event" if over_event_limit if tickets_applied.length > 0 str += ". We've applied your pass to #{ActionController::Base.helpers.pluralize(tickets_applied.length, 'ticket')} and left the others in your cart." end pass_errors << str end pass_errors.each { |err| self.errors.add(:base, err) } FeeCalculator.apply(FeeStrategy.new).to(cart) cart.save end end |
#cart_price ⇒ Object
44 45 46 |
# File 'app/models/pass.rb', line 44 def cart_price price end |
#exchangeable? ⇒ Boolean
75 76 77 |
# File 'app/models/pass.rb', line 75 def exchangeable? false end |
#expire! ⇒ Object
40 41 42 |
# File 'app/models/pass.rb', line 40 def expire! update_column(:ends_at, DateTime.now) end |
#expired? ⇒ Boolean
67 68 69 |
# File 'app/models/pass.rb', line 67 def expired? ends_at < Time.now end |
#realized_fee ⇒ Object
59 60 61 |
# File 'app/models/pass.rb', line 59 def realized_fee self.pass_type.hide_fee? ? self.price * PassType::SERVICE_FEE : 0 end |
#refundable? ⇒ Boolean
71 72 73 |
# File 'app/models/pass.rb', line 71 def refundable? true end |
#returnable? ⇒ Boolean
79 80 81 |
# File 'app/models/pass.rb', line 79 def returnable? false end |
#tickets_purchased ⇒ Object
We intentionally go to the DB here to avoid race conditions when applying a pass to the cart.
Method could cause problems in very large N+1 situations. Where up-to-date accuracy isn’t needed, Pass.includes(:tickets).tickets.length might be better
55 56 57 |
# File 'app/models/pass.rb', line 55 def tickets_purchased Ticket.where(:pass_id => self.id).count end |
#tickets_remaining_for(event) ⇒ Object
106 107 108 109 110 111 112 113 114 115 |
# File 'app/models/pass.rb', line 106 def tickets_remaining_for(event) @ept = EventsPassType.active .where(:organization_id => self.organization_id) .where(:event_id => event.id) .where(:pass_type_id => self.pass_type_id).first return 0 if @ept.nil? return self.tickets_allowed if @ept.limit_per_pass.nil? return @ept.limit_per_pass - event.tickets.where(:pass_id => self.id).count end |