Class: Subscription

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
app/models/subscription.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#current_passwordObject

Returns the value of attribute current_password.



14
15
16
# File 'app/models/subscription.rb', line 14

def current_password
  @current_password
end

Instance Method Details

#allowed_plansObject

list of plans this subscriber is allowed to choose use the subscription_plan_check callback in subscriber model



154
155
156
# File 'app/models/subscription.rb', line 154

def allowed_plans
  SubscriptionPlan.all.collect {|plan| plan unless exceeds_plan?(plan) }.compact
end

#cancelObject

cancelling can mean revert to a free plan and credit back their card if it also means destroying or disabling the user account, that happens elsewhere in your app returns same results as change_plan (nil, false, true)



99
100
101
102
103
# File 'app/models/subscription.rb', line 99

def cancel
  change_plan SubscriptionPlan.default_plan
  # uncomment if you want to refund unused value to their credit card, otherwise it just says on balance here
  #credit_balance
end

#change_plan(new_plan) ⇒ Object

returns nil if no change, false if failed, or true on success



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

def change_plan( new_plan )
  # not change?
  return if plan == new_plan
  
  # return unused prepaid value on current plan
  self.balance -= plan.prorated_value( days_remaining ) if SubscriptionConfig.return_unused_balance && active?
  # or they owe the used (although unpaid) value on current plan [comment out if you want to be more forgiving]
  self.balance -= plan.rate - plan.prorated_value( past_due_days ) if past_due?
  
  # update the plan
  self.plan = new_plan
  
  # update the state and initialize the renewal date
  if plan.free?
    self.free
    
  elsif (e = trial_ends_on)
    self.trial
    self.next_renewal_on = e #reset end date
  
  else #active or past due
    # note, past due grace period resets like active ones due today, ok?
    self.active
    self.next_renewal_on = Time.zone.today
    self.warning_level = nil
  end
  # past_due and expired fall through till next renew
  
  # save changes so far
  save
end

#charge_balanceObject


charge the current balance against the subscribers credit card

return amount charged on success, false for failure, nil for nothing happened



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'app/models/subscription.rb', line 171

def charge_balance
  #debugger
  # nothing to charge? (0 or a credit)
  return if balance_cents <= 0
  # no cc on fle
  return false if profile.no_info? || profile.profile_key.nil?

  transaction do # makes this atomic
    #debugger
    # charge the card
    tx  = SubscriptionTransaction.charge( balance, profile.profile_key )
    # save the transaction
    transactions.push( tx )
    # set profile state and reset balance
    if tx.success
      self.update_attribute :balance_cents, 0
      profile.authorized
    else
      profile.error
    end
    tx.success && tx.amount
  end
end

#credit_balanceObject

credit a negative balance to the subscribers credit card returns amount credited on success, false for failure, nil for nothing



217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'app/models/subscription.rb', line 217

def credit_balance
  #debugger
  # nothing to credit?
  return if balance_cents >= 0
  # no cc on fle
  return false if profile.no_info? || profile.profile_key.nil?

  transaction do # makes this atomic
    #debugger
    # credit the card
    tx  = SubscriptionTransaction.credit( -balance_cents, profile.profile_key, :subscription => self )
    # save the transaction
    transactions.push( tx )
    # set profile state and reset balance
    if tx.success
      self.update_attribute :balance_cents, 0
      profile.authorized
    else
      profile.error
    end
    tx.success && tx.amount
  end
end

#days_remainingObject

number of days until next renewal



266
267
268
# File 'app/models/subscription.rb', line 266

def days_remaining
  (next_renewal_on - Time.zone.today) unless next_renewal_on.nil?
end

#due?(days_from_now = 0) ⇒ Boolean


true if account is due today or before

Returns:

  • (Boolean)


243
244
245
# File 'app/models/subscription.rb', line 243

def due?( days_from_now = 0)
  days_remaining && (days_remaining <= days_from_now)
end

#exceeds_plan?(plan = self.plan) ⇒ Boolean

test if subscriber can use a plan, returns true or false

Returns:

  • (Boolean)


159
160
161
# File 'app/models/subscription.rb', line 159

def exceeds_plan?( plan = self.plan)
  !(plan_check(plan).blank?)
end

#grace_days_remainingObject

number of days until account expires



276
277
278
# File 'app/models/subscription.rb', line 276

def grace_days_remaining
  (next_renewal_on + SubscriptionConfig.grace_period.days - Time.zone.today) if past_due?
end

#latest_transactionObject

most recent transaction



281
282
283
# File 'app/models/subscription.rb', line 281

def latest_transaction
  transactions.first
end

#manual_charge_balanceObject


charge the current balance return amount charged on success, nil for nothing happened



198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'app/models/subscription.rb', line 198

def manual_charge_balance
  #debugger
  # nothing to charge? (0 or a credit)
  return if balance_cents <= 0

  transaction do # makes this atomic
    #debugger
    # charge the card
    tx  = SubscriptionTransaction.new(:success => true, :message => 'Successfull', :action => 'Manual Charge', :amount_cents => balance_cents)
    # save the transaction
    transactions.push( tx )
    self.update_attribute :balance_cents, 0
    self.active
    tx.success && tx.amount
  end
end

#past_due_daysObject

number of days account is past due (negative of days_remaining)



271
272
273
# File 'app/models/subscription.rb', line 271

def past_due_days
  (Time.zone.today - next_renewal_on) unless next_renewal_on.nil?
end

#plan_check(plan = self.plan) ⇒ Object

check if subscriber can use a plan and returns list of attributes exceeded, or blank for ok



164
165
166
# File 'app/models/subscription.rb', line 164

def plan_check( plan = self.plan)
  subscriber.subscription_plan_check(plan)       
end

#renewObject

returns nil if not past due, false for failed, true for success, or amount charged for success when card was charged



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'app/models/subscription.rb', line 70

def renew
  # make sure it's time
  return nil unless due?
  transaction do # makes this atomic
    #debugger
    # adjust current balance (except for re-tries)
    self.balance += plan.rate unless past_due?
    
    # charge the amount due
    case charge = charge_balance
      # transaction failed: past due and return false
      when false then
        Rails.logger.debug 'transaction failed: past due and return false'   
        past_due && false
      # not charged, subtracted from current balance: update renewal and return true
      when nil then
        Rails.logger.debug 'not charged, subtracted from current balance: update renewal and return true'
        active && true
      # card was charged: update renewal and return amount
      else
        Rails.logger.debug 'card was charged: update renewal and return amount'
        active && charge
    end
  end
end

#setup_activeObject



59
60
61
62
63
# File 'app/models/subscription.rb', line 59

def setup_active
  # next renewal is from when subscription ran out (to change this behavior, set next_renewal to nil before doing renew)
  start = next_renewal_on || Time.zone.today
  self.next_renewal_on = start + plan.interval.months
end

#setup_expiredObject



65
66
67
# File 'app/models/subscription.rb', line 65

def setup_expired
  change_plan SubscriptionPlan.expired_plan
end

#setup_freeObject



50
51
52
# File 'app/models/subscription.rb', line 50

def setup_free
  self.next_renewal_on = nil 
end

#setup_trialObject



54
55
56
57
# File 'app/models/subscription.rb', line 54

def setup_trial
  start = Time.zone.today
  self.next_renewal_on = start + SubscriptionConfig.trial_period.days
end

#trial_ends_onObject

date trial ends, or nil if not eligable



248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'app/models/subscription.rb', line 248

def trial_ends_on
  # no trials?
  return if SubscriptionConfig.trial_period.to_i==0
  case 
    # in trial, days remaining
    when trial?     then    next_renewal_on
    # new record? would start from today
    when plan.nil?  then    Time.zone.today + SubscriptionConfig.trial_period.days
    # start or continue a trial? prorate since creation
    #when active?    :
  else
        d = created_at.to_date + SubscriptionConfig.trial_period.days
                         d unless d <= Time.zone.today
    # else nil not eligable
  end
end