Recurring Invoice Logic

Never done recurring invoices before so wondering if this logic makes
sense:

Cron job runs at 4am each night and runs some ruby like this:

pseudocode:

For Each Invoice.due_date == Date.today
Invoice.new(:due_date => Date.today + 30)
Invoice.Save
End

Yeah, running a nightly cron job to create invoices make plenty of
sense.

This sounds good. Although for clarity, you might use “generated_date”
in addition to “due_date”. It seems odd to have the date the invoice
is due is the date it’s created. (actually, the created_at would be
the generated date so it’s probably redundant)

I would keep the logic of an “Invoice” separate from a “Schedule”. So
maybe you have a ScheduleInvoice object that holds a “next_run” field.
Then, to add an invoice to the system, you’d create a new
ScheduleInvoice object and set the next_run field to be when it should
be generated (or if generated when created, then the next_run would be
a month later).

I could see, then, some simple code running in a cron:

ScheduleInvoice.find_all_by_next_run(Date.today).each do |schedule|
invoice = Invoice.new(:due_date => 30.days.from_now)
if invoice.save
schedule.next_run = 1.month.from_now
else
# handle the failure
end
end

At least, that’s how I’d do it. In fact, I’ll need to soon for a
project I’m building. Good to think through this a little.

-Danimal

Your idea of a next_run is exactly what I needed. I built a cron job
and it is working but I was afraid of having redundant invoices made
incase, for some reason the cron job ran twice a day or something.
This is what my cron job looks like below but I think I will alter it
to include some next_run logic.

@invoices = Invoice.find(:all)
@invoices.each do |invoice|
if invoice.due_date == Date.today # and the user does not have
an invoice due in 30 days
@invoice = Invoice.new
@invoice.generated_date = Date.today
@invoice.amount = “14.95”
@invoice.due_date = 1.month.from_now
@invoice.status = “Due”
@invoice.user_id = invoice.user_id
@invoice.save
puts “Invoice #{@invoice.id} created for #
{invoice.user.first_name} #{invoice.user.last_name} due #
{@invoice.due_date}”
end
end

Thanks

Jason

On Mar 31, 2008, at 7:40 AM, Danimal wrote:

This sounds good. Although for clarity, you might use “generated_date”
in addition to “due_date”. It seems odd to have the date the invoice
is due is the date it’s created. (actually, the created_at would be
the generated date so it’s probably redundant)

I would keep the logic of an “Invoice” separate from a “Schedule”. So
maybe you have a ScheduleInvoice object that holds a “next_run” field.
Then, to add an invoice to the system, you’d create a new
ScheduleInvoice object and set the next_run field to be when it should
be generated (or if generated when created, then the next_run would be
a month later).

I could see, then, some simple code running in a cron:

ScheduleInvoice.find_all_by_next_run(Date.today).each do |schedule|
invoice = Invoice.new(:due_date => 30.days.from_now)
if invoice.save
schedule.next_run = 1.month.from_now
else
# handle the failure
end
end

At least, that’s how I’d do it. In fact, I’ll need to soon for a
project I’m building. Good to think through this a little.

-Danimal