def main():
    """
    Find subscriptions that are due to be invoiced, generate the invoices, 
    update the accounts, update the subscription and kill all humans
    """

    invoices = []
    try:
        # Get current subscriptions and subscriptions that have not been (fully) invoiced and are due to be invoiced.
        subscriptions = Subscription.objects.filter(active = 1)
        subscriptions = subscriptions.filter(Q(invoiced_until_date__isnull = True) | Q(invoiced_until_date__gte = F('start_date')))
        subscriptions = subscriptions.filter(Q(end_date__isnull = True) | Q(invoiced_until_date__lte = F('end_date')))
        subscriptions = subscriptions.filter(Q(invoiced_until_date__isnull = True) | Q(invoiced_until_date__lte = datetime.utcnow()))

        for subscription in subscriptions:
            invoice = Invoice()
            invoice.customer = subscription.customer
            invoice.date = date.today()
            invoice.save()

            if subscription.invoiced_until_date:
                start_date = subscription.invoiced_until_date
            else:
                start_date = subscription.start_date

            # Invoice every invoice period that needs to be invoiced.
            while start_date < datetime.utcnow():
                #
                # Calculate the date until which we are invoicing
                #
    
                if subscription.product.invoice_interval == 0:
                    subscription.invoiced_until_date = start_date + timedelta(days = subscription.product.invoice_interval_count * subscription.intervals_per_invoice)

                if subscription.product.invoice_interval == 1:
                    subscription.invoiced_until_date = start_date + timedelta(weeks = subscription.product.invoice_interval_count * subscription.intervals_per_invoice)

                elif subscription.product.invoice_interval == 2:
                    months = subscription.product.invoice_interval_count * subscription.intervals_per_invoice
                    month = start_date.month + months % 12
                    year = start_date.year + int(months / 12)
                    subscription.invoiced_until_date = datetime(year, month, start_date.day, 0, 0, 0)

                elif subscription.product.invoice_interval == 3:
                    quarters = subscription.product.invoice_interval_count * subscription.intervals_per_invoice
                    month = start_date.month + (quarters * 3) % 12
                    year = start_date.year + int((quarters * 3) / 12)
                    subscription.invoiced_until_date = datetime(year, month, start_date.day, 0, 0, 0)
    
                elif subscription.product.invoice_interval == 4:
                    years = subscription.product.invoice_interval_count * subscription.intervals_per_invoice
                    subscription.invoiced_until_date = datetime(start_date.year + years, month, day, 0, 0, 0)

                # Add the subscription lines to the invoice
                invoiceitem = InvoiceItem()
                invoiceitem.invoice = invoice
                invoiceitem.item = None # Only used for products with serials
                invoiceitem.product = subscription.product
                invoiceitem.period = start_date.strftime("%Y-%m-%d") + " - " + subscription.invoiced_until_date.strftime("%Y-%m-%d")
                invoiceitem.description = subscription.extra_info
                invoiceitem.count = 1
                invoiceitem.amount = subscription.product.get_price()
                if invoiceitem.amount == None:
                    # This item has no price
                    raise LookupError
    
                invoiceitem.amount *= subscription.intervals_per_invoice
                invoiceitem.vat = subscription.product.vat
                invoiceitem.save()

                start_date = subscription.invoiced_until_date

            # This subscription has been invoiced.
            subscription.save()

            # The transactions should be made to the VAT tables and accounts receivable
            invoice.book()        

            invoices.append(invoice)

    except:
        db_trans.rollback()
        raise
    else:
        db_trans.commit()

    for invoice in invoices:
            # Mail the invoice to the client if requested, otherwise put the PDF in the outgoing snailmail queue
            if invoice.customer.invoice_by_email:
                pdf = invoice.pdf()
                send_mail("%s <%s>" % (invoice.customer.displayname, invoice.customer.invoice_email), invoice.full_invoice_no, pdf)
            else:
                # FIXME Snailmail queue should be here
                pass
    db_trans.commit()