Recurring Invoices

After creating a single invoice is there a way to use workflow to then create a new invoice for the following month. In essence, setting up a recurring invoice? Thank you

I have done this before using an after save logic hook. We made ours trigger on payment and the period was variable so that you don’t end up with more than 1 outstanding invoice for a client. If you would like I can make the code available, you will need to modify it a bit as it alters a lot of custom fields in our system.

The real trick is in getting it to duplicate the line items and associate them with the new invoice (AOS_Invoices module is a little different to most others).

I will pull the code when I have a chance later today.


HN Software Consulting

Sam, could I take you up on your offer of the code for this?

Many thanks,

Sure I will pull it down for you later today.

This is an example of the code to duplicate an invoice. I had to run an SQL query to retrieve a set of invoices for our workflow, you wouldn’t need to do it in a loop if you just want to duplicate one obviously. I have tried to trim it down so you don’t have to navigate through a bunch of our custom fields that are edited in the script.

Other things to note, I am setting the status to “Paid” here, if you were creating future invoices you can just set the Status empty and it will return to your default; we also set the Invoice date and Paid date based on a parameter that is passed earlier, this would probably change for you.


                $result = $bean->db->query($sql);
                while ($rawRow = $bean->db->fetchByAssoc($result)) {
                    $invoice = new AOS_Invoices();
                    $old_id = $rawRow['id'];

                    $rawRow['id'] = '';
                    $rawRow['name'] = '';
                    $rawRow['number'] = '';
                    $rawRow['status'] = 'Paid';

                    $invoice->invoice_date = $date;
                    $invoice->amount_paid_c = $invoice->total_amount;
                    $invoice->date_paid_c = $date;

                    $sql2 = "SELECT * FROM aos_products_quotes WHERE parent_type = 'AOS_Invoices' AND parent_id = '".$old_id."' AND deleted = 0";
                    $GLOBALS['log']->fatal("SQL2: ". $sql2);

                    $result2 = $bean->db->query($sql2);
                    while ($row2 = $bean->db->fetchByAssoc($result2)) {
                        $GLOBALS['log']->fatal("second while loop");
                        $row2['id'] = '';
                        $row2['parent_id'] = $invoice->id;
                        $row2['parent_type'] = 'AOS_Invoices';
                        if($row2['product_cost_price'] != null)
                                $row2['product_cost_price'] = format_number($row['product_cost_price']);
                        $row2['product_list_price'] = format_number($row2['product_list_price']);
                        if($row2['product_discount'] != null)
                                $row2['product_discount'] = format_number($row2['product_discount']);
                                $row2['product_discount_amount'] = format_number($row2['product_discount_amount']);
                        $row2['product_unit_price'] = format_number($row2['product_unit_price']);
                        $row2['vat_amt'] = format_number($row2['vat_amt']);
                        $row2['product_total_price'] = format_number($row2['product_total_price']);
                        $row2['product_qty'] = format_number($row2['product_qty']);
                        $prod_invoice = new AOS_Products_Quotes();

When trying to set up a recurring invoicing regime, I have taken the path of running it using a scheduled task and a custom module.
It’s very flexible, and can be completely automated.

The idea is that you create a custom scheduled task (which can run daily). This goes through your list of accounts looking for your custom module (Recurring Invoice) which sets up the details for the Invoice. These details can be day of month/year in which invoice is generated, $amount, Description, etc… Then it generates an unpaid Invoice, and links it to the account.

It’s the same basic concepts required to write a logic hook.

Help with custom task schedulers:

Help with relationships within custom modules

Reminder that the relationships must be loaded before they are set…