Class: Billingly::Tasks

Inherits:
Object
  • Object
show all
Defined in:
app/models/billingly/tasks.rb

Overview

The Tasks model has all the tasks that should be run periodically through rake. A special log is created for the tasks being run and the results are reported back to the website administrator.

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#endedDateTime

The date in which the tasks ended

Returns:

  • (DateTime)


13
14
15
# File 'app/models/billingly/tasks.rb', line 13

def ended
  @ended
end

#extendedFile

A detailed description of errors that ocurred while running all the tasks.

Returns:

  • (File)


24
25
26
# File 'app/models/billingly/tasks.rb', line 24

def extended
  @extended
end

#startedDateTime

The date in which the tasks started running.

Returns:

  • (DateTime)


8
9
10
# File 'app/models/billingly/tasks.rb', line 8

def started
  @started
end

#summaryString

A summary of all the tasks that were run and their overall results.

Returns:

  • (String)


18
19
20
# File 'app/models/billingly/tasks.rb', line 18

def summary
  @summary
end

Instance Method Details

#batch_runner(task_name, method, &collection_getter) ⇒ Object

The batch runner is a helper function for running a method on each item of a collection logging the results, without aborting excecution if calling the rest of the items if any of them fails.

The method called on each item will not receive parameters and should return a Truthy value if successfull, or raise an exception otherwise. Returning nil means that there was nothing to be done on that item.

The collection to be used should be returned by a block provided to this method. Any problem fetching the collection will also be universally captured

See #generate_next_invoices for an example use.

Parameters:

  • task_name (String)

    the name to use for this task in the generated log.

  • method (Symbol)

    the method to call on each one of the given items.

  • collection_getter (Proc)

    a block which should return the collection to use.



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'app/models/billingly/tasks.rb', line 76

def batch_runner(task_name, method, &collection_getter)
  collection = begin
    collection_getter.call
  rescue Exception => e
    failure += 1
    log_extended("#{task_name}:\nCollection getter failed\n#{e.message}\n\n#{e.backtrace}")
    return
  end

  success = 0
  failure = 0

  collection.each do |item|
    begin
      success += 1 if item.send(method)
    rescue Exception => e
      failure += 1
      log_extended("#{task_name}:\n#{e.message}\n#{item.inspect}\n\n#{e.backtrace}")
    end
  end

  if failure == 0
    log_summary("Success: #{task_name}, #{success} OK.")
  else
    log_summary("Failure: #{task_name}, #{success} OK, #{failure} failed.")
  end
end

#charge_invoicesObject

Charges all invoices for which the customer has enough balance. Oldest invoices are charged first, newer invoices should not be charged until the oldest ones are paid. See Invoice#Charge for more information on how invoices are charged from the customer’s balance.

Parameters:

  • collection (Array<Invoice>)

    The list of invoices to attempt charging. Defaults to all invoices in the system.



122
123
124
125
126
127
128
129
# File 'app/models/billingly/tasks.rb', line 122

def charge_invoices
  batch_runner('Charging pending invoices', :charge_pending_invoices) do
    Billingly::Customer
      .joins(:invoices)
      .where(billingly_invoices: {deleted_on: nil, paid_on: nil})
      .readonly(false)
  end
end

#deactivate_all_debtorsObject

This method will deactivate all customers who have overdue Invoices.

This only deactivates the debtor, it does not notify them via email. Look at #notify_all_overdue to see the email notification customers receive.

See Customer#deactivate_debtor for more info on how debtors are deactivated.



178
179
180
181
182
# File 'app/models/billingly/tasks.rb', line 178

def deactivate_all_debtors
  batch_runner('Deactivating Debtors', :deactivate_debtor) do
    Billingly::Customer.debtors.where(deactivated_since: nil).readonly(false)
  end
end

#deactivate_all_expired_trialsObject

Customers may be subscribed for a trial period, and they are supposed to re-subscribe before their trial expires.

When their trial expires and they have not yet subscribed to another plan, we deactivate their account immediately. This method does not email them about the expired trial.

See Customer#deactivate_trial_expired for more info on how trials are deactivated.



193
194
195
196
197
198
199
# File 'app/models/billingly/tasks.rb', line 193

def deactivate_all_expired_trials
  batch_runner('Deactivating Expired Trials', :deactivate_trial_expired) do
    Billingly::Customer.joins(:subscriptions).readonly(false)
      .where("#{Billingly::Subscription.table_name}.is_trial_expiring_on < ?", Time.now)
      .where(billingly_subscriptions: {unsubscribed_on: nil})
  end
end

#generate_next_invoicesObject

Invoices for running subscriptions which are not trials are generated by this task. See Subscription#generate_next_invoice for more information about how the next invoice for a subscription is created.



107
108
109
110
111
112
113
# File 'app/models/billingly/tasks.rb', line 107

def generate_next_invoices
  batch_runner('Generating Invoices', :generate_next_invoice) do
    Billingly::Subscription
      .where(is_trial_expiring_on: nil, unsubscribed_on: nil)
      .readonly(false)
  end
end

#log_extended(text) ⇒ Object

Writes a line to the #extended section of this tasks results report.

Parameters:

  • text (String)


45
46
47
48
49
50
51
# File 'app/models/billingly/tasks.rb', line 45

def log_extended(text)
  if self.extended.nil?
    time = Time.now.utc.strftime("%Y%m%d%H%M%S")
    self.extended = File.open("#{Rails.root}/log/billingly_#{time}.log", 'w')
  end
  self.extended.write("#{text}\n\n")
end

#log_summary(text) ⇒ Object

Writes a line to the #summary section of this task results report.

Parameters:

  • text (String)


55
56
57
58
# File 'app/models/billingly/tasks.rb', line 55

def log_summary(text)
  self.summary ||= ''
  self.summary += "#{text}\n"
end

#notify_all_overdueObject

This task notifies customers when one of their invoices is overdue. Overdue invoices go together with account deactivations so the email sent by this task also includes the deactivation notice.

This task does not perform the actual deactivation, #deactivate_all_debtors does.

See Invoice#notify_overdue for more info on how overdue invoices are notified.



162
163
164
165
166
167
168
169
# File 'app/models/billingly/tasks.rb', line 162

def notify_all_overdue
  batch_runner('Notifying Pending Invoices', :notify_overdue) do
    Billingly::Invoice
      .where('due_on <= ?', Time.now)
      .where(deleted_on: nil, paid_on: nil, notified_overdue_on: nil)
      .readonly(false)
  end
end

#notify_all_paidObject

Notifies invoices that have been charged successfully, sending a receipt. See Invoice#notify_paid for more information on how receipts are sent for paid invoices.



134
135
136
137
138
139
140
141
# File 'app/models/billingly/tasks.rb', line 134

def notify_all_paid
  batch_runner('Notifying Paid Invoices', :notify_paid) do
    Billingly::Invoice
      .where('paid_on is not null')
      .where(deleted_on: nil, notified_paid_on: nil)
      .readonly(false)
  end
end

#notify_all_pendingObject

Customers are notified about their pending invoices by this task. See Invoice#notify_pending for more info on how pending invoices are notified.



146
147
148
149
150
151
152
# File 'app/models/billingly/tasks.rb', line 146

def notify_all_pending
  batch_runner('Notifying Pending Invoices', :notify_pending) do
    Billingly::Invoice
      .where(deleted_on: nil, paid_on: nil, notified_pending_on: nil)
      .readonly(false)
  end
end

#run_allObject

Runs all of Billingly’s periodic tasks and creates a report with the results at the end.



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'app/models/billingly/tasks.rb', line 27

def run_all
  self.started = Time.now

  generate_next_invoices
  charge_invoices
  deactivate_all_debtors
  deactivate_all_expired_trials
  notify_all_paid
  notify_all_pending
  notify_all_overdue

  self.ended = Time.now
  self.extended.close unless self.extended.nil?
  Billingly::Mailer.task_results(self).deliver
end