Class: Registration

Inherits:
ActiveRecord::Base
  • Object
show all
Includes:
DmCore::Concerns::HasCustomFields, DmEvent::Concerns::RegistrationStateEmail, DmEvent::Concerns::RegistrationStateMachine, OffsitePayments::Integrations
Defined in:
app/models/registration.rb

Overview

Important: one reason to link off of the user_profile instead of the user is so that we can support registrations without requiring an account. We can create a “userless” profile, that has all the necessary information. This is instead of duplicating all those fields in the registration table.


Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#payment_comment_textObject

Returns the value of attribute payment_comment_text.



22
23
24
# File 'app/models/registration.rb', line 22

def payment_comment_text
  @payment_comment_text
end

Class Method Details

.csv_columns(workshop) ⇒ Object

Setup the columns for exporting data as csv.




231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# File 'app/models/registration.rb', line 231

def self.csv_columns(workshop)
  column_definitions = []
  column_definitions <<     ["Receipt Code",      "'R-' + item.receipt_code", 75] # 'R-' makes sure Numbers treats as a String, not a Date
  column_definitions <<     ['Process State',     'item.aasm_state', 100]
  column_definitions <<     ["Full Name",         "item.full_name", 100]
  column_definitions <<     ["Last Name",         "item.last_name.capitalize", 100]
  column_definitions <<     ["First Name",        "item.first_name.capitalize", 100]
  column_definitions <<     ["Email",             "item.email.downcase", 150]
  column_definitions <<     ["Address",           "item.address", 150]
  column_definitions <<     ["Address2",          "item.address2"]
  column_definitions <<     ["City",              "item.city.capitalize", 100]
  column_definitions <<     ["State",             "item.state.capitalize"]
  column_definitions <<     ["Zipcode",           "item.zipcode"]
  column_definitions <<     ["Country",           "item.country.code"]
  column_definitions <<     ['Registered on',     'item.created_at.to_date', 75, {type: 'DateTime', numberformat: 'd mmm, yyyy'}]
  column_definitions <<     ["Price",             "item.workshop_price.price.to_f", nil, {type: 'Number', numberformat: '#,##0.00'}]
  column_definitions <<     ["Price Description", "item.workshop_price.price_description"]
  column_definitions <<     ["Price Sub Descr",   "item.workshop_price.sub_description"]
  column_definitions <<     ["Discount",          "item.discount.to_f", nil, {type: 'Number', numberformat: '#,##0.00'}]
  column_definitions <<     ["Paid",              "item.amount_paid.to_f", nil, {type: 'Number', numberformat: '#,##0.00'}]
  column_definitions <<     ["Balance",           "item.balance_owed.to_f", nil, {type: 'Number', numberformat: '#,##0.00'}]

  # ---- add the extra fields defined in the workshop record
  workshop.custom_field_defs.each_with_index do | x, index |
    case x.field_type
    when 'check_box_collection'
      column_definitions << [ "#{x.column_name}", "(z = item.custom_fields.detect { |y| y.custom_field_def_id == #{x.id} }) ? z.value : ''", nil, {type: 'list', custom_field: true}]
    when 'divider'
    else
      column_definitions << [ "#{x.column_name}", "(z = item.custom_fields.detect { |y| y.custom_field_def_id == #{x.id} }) ? z.value : ''", nil, {custom_field: true}]
    end
  end
  return column_definitions
end

.number_of(state, options = {}) ⇒ Object

Return the number of items specified, in particular the number of items in a particular state




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
# File 'app/models/registration.rb', line 149

def self.number_of(state, options = {})
  query = (options[:only_confirmed] ? where.not(confirmed_on: nil) : all)
  case state
  when :attending
    attending.count
  when :unpaid
    #--- the number of unpaid is the same as the number of accepted
    number_of(:accepted)
  when :checkedin
    query.where.not(checkin_at: 0).where(archived_on: nil).count
  when :archived
    query.where.not(archived_on: nil).count
  when :registrations
    #--- don't count any canceled
    query.where(archived_on: nil).where.not(aasm_state: 'canceled').where.not(aasm_state: 'refunded').count
  when :at_price
    #--- number of registrations for a particular price
    query.where(archived_on: nil).where("(aasm_state = 'paid' OR aasm_state = 'accepted')").where(workshop_price_id: options[:price_id]).count
  when :for_all_prices
    #--- array of counts per price
    query.where(archived_on: nil).where("(aasm_state = 'paid' OR aasm_state = 'accepted')").group(:workshop_price_id).count
  when :discounted
    attending.discounted.count
  when :discounted_total
    total = attending.discounted.to_a.sum(&:discount)
    (total == 0) ? Money.new(0) : total
  when :user_updated
    #--- how many users updated their record
    query.where(archived_on: nil).where("(aasm_state = 'paid' OR aasm_state = 'accepted')").where.not(user_updated_at: nil).count
  when :confirmed
    #--- how many users confirmed their attendance
    where.not(confirmed_on: nil).where(archived_on: nil).where("(aasm_state = 'paid' OR aasm_state = 'accepted')").count
  else
    #--- must be wanting to count the process states
    query.where(archived_on: nil, aasm_state: state).count
  end
end

.receiptcode_to_id(receiptcode) ⇒ Object

receipt code is simply the record id + 1100




83
84
85
# File 'app/models/registration.rb', line 83

def self.receiptcode_to_id(receiptcode)
  return receipt_code.split('-')[1].to_i
end

Instance Method Details

#balance_owedObject

Return the amount still owed, based on the current payments made. balance_owed is positive if payment is still required. Negative if there has been an overpayment




115
116
117
# File 'app/models/registration.rb', line 115

def balance_owed
  discounted_price - amount_paid
end

#delete_payment(payment_id) ⇒ Object

delete a payment and update the registrations total amount paid




317
318
319
320
321
322
323
324
325
326
327
# File 'app/models/registration.rb', line 317

def delete_payment(payment_id)
  payment = PaymentHistory.find(payment_id)
  if payment
    self.update_attribute(:amount_paid_cents, (self.amount_paid - self.workshop_price.to_base_currency(payment.total)).cents)
    payment.destroy
    suppress_transition_email
    self.send('accept!') if balance_owed.positive? && self.paid?
    return true
  end
  return false
end

#discountObject




100
101
102
103
104
105
106
107
108
109
# File 'app/models/registration.rb', line 100

def discount
  return Money.new(0, workshop.base_currency) if workshop_price.nil? || workshop_price.price.nil?

  unless discount_value.blank?
    cents = (discount_use_percent ? (workshop_price.price.cents * discount_value / 100) : (discount_value * 100))
  else
    cents = 0
  end
  Money.new(cents, workshop_price.price.currency)
end

#discounted_priceObject

Price with discount




95
96
97
# File 'app/models/registration.rb', line 95

def discounted_price
  price - discount
end

#last_payment_due_onObject

date when the most recent payment was due




224
225
226
227
# File 'app/models/registration.rb', line 224

def last_payment_due_on
  entry = workshop_price.specific_payment_schedule(self.created_at, Date.today)
  entry ? entry[:due_on] : self.created_at.to_date
end

#make_payment_now_amountObject

when a customer wants to make a payment, they should either charged the amount for this month (which could be less than the normal monthly amount), or the standard monthly amount, or whatever the balance_owed is




136
137
138
139
140
141
142
143
144
# File 'app/models/registration.rb', line 136

def make_payment_now_amount
  if payment_owed.positive?
    payment_owed
  elsif workshop_price.payment_price < balance_owed
    workshop_price.payment_price
  else
    balance_owed
  end
end

#manual_payment(payment_history, cost, total_currency, user_profile, options = { item_ref: '', payment_method: 'cash', bill_to_name: '', payment_date: Time.now, notify_data: nil, transaction_id: nil, status: '' }) ⇒ Object

Payment was entered manually, create the history record. You can tell it’s a manual entry if the user_profile is filled in - means a human did it.




269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
# File 'app/models/registration.rb', line 269

def manual_payment(payment_history, cost, total_currency, ,
                   options = { item_ref: '', payment_method: 'cash', bill_to_name: '', payment_date: Time.now,
                               notify_data: nil, transaction_id: nil, status: '' } )
  amount            = Monetize.parse(cost, total_currency)
  
  if payment_history
    new_amount_paid = self.amount_paid - self.workshop_price.to_base_currency(payment_history.total) + self.workshop_price.to_base_currency(amount)
    payment_history.update_attributes(
      item_ref: options[:item_ref],
      cost: cost,
      total_cents: amount.cents,
      total_currency: amount.currency.iso_code,
      payment_method: options[:payment_method],
      bill_to_name: options[:bill_to_name],
      payment_date: options[:payment_date],
      user_profile_id: .id)
  else
    new_amount_paid = self.amount_paid + self.workshop_price.to_base_currency(amount)
    payment_history   = self.payment_histories.create(
        anchor_id: receipt_code,
        item_ref: options[:item_ref],
        cost: cost,
        quantity: 1,
        discount: 0,
        total_cents: amount.cents,
        total_currency: amount.currency.iso_code,
        payment_method: options[:payment_method],
        bill_to_name: options[:bill_to_name],
        payment_date: options[:payment_date],
        user_profile_id: ( ? .id : nil),
        notify_data: options[:notify_data],
        transaction_id: options[:transaction_id],
        status: ( ? "Completed" : options[:status])
    )
  end
      
  if payment_history.errors.empty?
    self.update_attribute(:amount_paid_cents, new_amount_paid.cents)
    self.reload
    self.send('paid!') if balance_owed.cents <= 0 && self.accepted?
  else
    logger.error("===> Error: Registration.manual_payment: #{payment_history.errors.inspect}")
  end
  return payment_history
end

#past_due?(grace_period_in_days = 7) ⇒ Boolean

past due means they haven’t paid what they should have paid by now


Returns:

  • (Boolean)


207
208
209
210
211
212
213
214
# File 'app/models/registration.rb', line 207

def past_due?(grace_period_in_days = 7)
  return false if !balance_owed.positive?
  if workshop_price.recurring_payments?
    return amount_paid < recurring_what_should_be_paid_by_now(grace_period_in_days)
  else
    return Date.today > (self.created_at + grace_period_in_days.days)
  end
end

#payment_owedObject

suggested amount of next payment. when it’s recurring, they payment should be whatever is needed to bring their payment plan up to date




123
124
125
126
127
128
129
130
# File 'app/models/registration.rb', line 123

def payment_owed
  if workshop_price && workshop_price.recurring_payments?
    to_pay = recurring_what_should_be_paid_by_now(0) - amount_paid
    to_pay.negative? ? Money.new(0, workshop_price.price.currency) : to_pay
  else
    balance_owed
  end
end

#payment_reminder_due?Boolean

Is it time to send a payment reminder? Due first 7 days after inital registration (or a payment period). Then every 14 days after that


Returns:

  • (Boolean)


196
197
198
199
200
201
202
203
# File 'app/models/registration.rb', line 196

def payment_reminder_due?
  if preferred_payment_reminder_hold_until.nil? || preferred_payment_reminder_hold_until < Time.now
    time_period = self.payment_reminder_sent_on.nil? ? (self.created_at + 7.days) : (self.payment_reminder_sent_on + 14.days)
    past_due?(7) ? time_period < Time.now : false
  else
    false
  end
end

#payment_urlObject

Return the payment page url, so that it can be used in emails




331
332
333
# File 'app/models/registration.rb', line 331

def payment_url
  DmEvent::Engine.routes.url_helpers.register_choose_payment_url(self.uuid, host: Account.current.url_host, locale: I18n.locale)
end

#priceObject

Price of this registration (without discount)




89
90
91
# File 'app/models/registration.rb', line 89

def price
  (workshop_price && workshop_price.price) ? workshop_price.price : Money.new(0, workshop.base_currency)
end

#recurring_what_should_be_paid_by_now(grace_period_in_days = 7) ⇒ Object




217
218
219
220
# File 'app/models/registration.rb', line 217

def recurring_what_should_be_paid_by_now(grace_period_in_days = 7)
  entry = workshop_price.specific_payment_schedule(self.created_at + grace_period_in_days.days, Date.today)
  entry ? entry[:total_due] : 0
end

#unpaid?Boolean

check if the regsitration is unpaid


Returns:

  • (Boolean)


189
190
191
# File 'app/models/registration.rb', line 189

def unpaid?
  self.accepted? && self.archived_on == nil
end