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

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