示例#1
0
 def make_invoice(self, issuer):
     """Creates an invoice based on the current quotation/purchase order"""
     from invoicing.models import Invoice, InvoiceRevision
     # Initialize the invoice
     invoice = Invoice(
         full_init=False,
         tenant=self.tenant,
         account_type=self.account_type,
         issuer=issuer,
         organization=self.organization,
         contact=self.contact,
         related_to=self,
         group=self.group,
         attachments=self.attachments
     )
     
     # Save the invoice, based on the quotation/purchase order
     inv_data = invoice.add_revision(revision=InvoiceRevision(based_on=self.current_revision))
     inv_data.state = invoice.state
     inv_data.issuer = issuer
     inv_data.issue_date = datetime_now()
     inv_data.invoicing_date = datetime.date.today()
     inv_data.due_date = get_due_date(inv_data.invoicing_date, self.tenant.tenant_settings.invoicing.payment_conditions)
     invoice.save()
     
     # Update state
     if self.is_quotation():
         self.state = QUOTATION_STATES.INVOICED
     elif self.is_purchase_order():
         self.state = PURCHASE_ORDER_STATES.INVOICED
     self.save()
     return invoice
示例#2
0
def create(request):
    choice_member = Member.objects.all()
    if not request.POST:
        return render(request, 'invoice.html',
                      {'choice_member': choice_member})
    else:
        member_id = request.POST['member_id']

        invoice_number_max = Invoice.objects.all().aggregate(
            Max('invoice_number'))['invoice_number__max']
        invoice_number = invoice_number_max + 1

        member = Member.objects.get(pk=member_id)
        usages = Usage.objects.filter(member=member, valid=True, invoice=None)

        total_amount = usages.aggregate(total=Sum('total_price'))['total']

        invoice = Invoice(amount=total_amount,
                          member=member,
                          invoice_number=invoice_number)
        invoice.save()

        usages.update(invoice=invoice)
        usages = Usage.objects.filter(invoice=invoice)

        return render(
            request, 'invoice.html', {
                'usages': usages,
                'member_info': member,
                'choice_member': choice_member,
                'invoice': invoice
            })
示例#3
0
文件: mixins.py 项目: tcpr1/vosae-app
    def make_invoice(self, issuer):
        """Creates an invoice based on the current quotation/purchase order"""
        from invoicing.models import Invoice, InvoiceRevision
        # Initialize the invoice
        invoice = Invoice(full_init=False,
                          tenant=self.tenant,
                          account_type=self.account_type,
                          issuer=issuer,
                          organization=self.organization,
                          contact=self.contact,
                          related_to=self,
                          group=self.group,
                          attachments=self.attachments)

        # Save the invoice, based on the quotation/purchase order
        inv_data = invoice.add_revision(revision=InvoiceRevision(
            based_on=self.current_revision))
        inv_data.state = invoice.state
        inv_data.issuer = issuer
        inv_data.issue_date = datetime_now()
        inv_data.invoicing_date = datetime.date.today()
        inv_data.due_date = get_due_date(
            inv_data.invoicing_date,
            self.tenant.tenant_settings.invoicing.payment_conditions)
        invoice.save()

        # Update state
        if self.is_quotation():
            self.state = QUOTATION_STATES.INVOICED
        elif self.is_purchase_order():
            self.state = PURCHASE_ORDER_STATES.INVOICED
        self.save()
        return invoice
示例#4
0
def test_get_invoice(client):
    with db.connection() as DB:
        invoice = Invoice(amount=5, description='Test invoice')
        DB.add(invoice)

    response = client.get('/invoices/{0}/'.format(invoice.id))
    data = response.json
    data['amount'] = Decimal(data['amount'])
    data['amount_remaining'] = Decimal(data['amount_remaining'])

    invoice_details = invoice.to_json()
    invoice_details['created_at'] = invoice_details['created_at'].strftime(DATE_FORMAT)  # noqa
    invoice_details['updated_at'] = invoice_details['updated_at'].strftime(DATE_FORMAT)  # noqa

    assert data == invoice_details
示例#5
0
文件: imex.py 项目: tcpr1/vosae-app
def get_exportable_documents(export):
    documents = []
    if 'QUOTATION' in export.documents_types:
        full_export = Quotation.full_export(export.tenant, export.from_date, export.to_date)
        documents.append(full_export)
        serializer = QuotationCSVSerializer()
        documents.append((
            [serializer.serialize(full_export[0])],
            lambda buf: '{0}/{1}.csv'.format(_('Quotations'), _('Quotations')),
            lambda buf: buf
        ))

    if 'INVOICE' in export.documents_types:
        full_export = Invoice.full_export(export.tenant, export.from_date, export.to_date)
        documents.append(full_export)
        serializer = InvoiceCSVSerializer()
        documents.append((
            [serializer.serialize(full_export[0])],
            lambda buf: '{0}/{1}.csv'.format(_('Invoices'), _('Invoices')),
            lambda buf: buf
        ))

    if 'CREDIT_NOTE' in export.documents_types:
        full_export = CreditNote.full_export(export.tenant, export.from_date, export.to_date)
        documents.append(full_export)
        serializer = CreditNoteCSVSerializer()
        documents.append((
            [serializer.serialize(full_export[0])],
            lambda buf: '{0}/{1}.csv'.format(_('Credit notes'), _('Credit notes')),
            lambda buf: buf
        ))
    return documents
示例#6
0
 def forwards(self, orm):
     from invoicing.models import InvoiceBaseGroup
     # Process quotations
     for quotation in Quotation.objects():
         group = InvoiceBaseGroup(tenant=quotation.tenant, quotation=quotation).save()
         if quotation._data.get('down_payments'):
             group.down_payment_invoices = dereference(quotation._data.get('down_payments'), DownPaymentInvoice)
             for down_payment_invoice in group.down_payment_invoices:
                 down_payment_invoice.update(set__group=group)
         if quotation._data.get('related_invoice'):
             group.invoice = dereference(quotation._data.get('related_invoice'), Invoice)
             group.invoice.update(set__group=group)
         if quotation._data.get('related_invoices_cancelled'):
             group.invoices_cancelled = dereference(quotation._data.get('related_invoices_cancelled'), Invoice)
             for invoice_cancelled in group.invoices_cancelled:
                 invoice_cancelled.update(set__group=group)
         group.save()
         quotation.update(set__group=group)
     
     # Process invoices and down-payment invoices
     for invoice in Invoice.objects():
         if not invoice.group.id:
             # Can only be an invoice: down-payment invoices are linked to quotations, so group is set
             group = InvoiceBaseGroup(tenant=quotation.tenant, invoice=invoice).save()
             invoice.update(set__group=group)
         else:
             group = invoice.group
         if invoice._data.get('related_credit_note'):
             group.credit_notes = [dereference(invoice._data.get('related_credit_note'), CreditNote)]
             for credit_note in group.credit_notes:
                 credit_note.update(set__group=group, set__related_to=invoice)
         group.save()
示例#7
0
def test_list_invoices(client):
    with db.connection() as DB:
        invoice = Invoice(amount=5, description='Test invoice')
        DB.add(invoice)

    response = client.get('/invoices/')
    data = response.json
    for n in range(len(data)):
        data[n]['amount'] = Decimal(data[n]['amount'])
        data[n]['amount_remaining'] = Decimal(data[n]['amount_remaining'])

    invoice_details = invoice.to_json()
    invoice_details['created_at'] = invoice_details['created_at'].strftime(DATE_FORMAT)  # noqa
    invoice_details['updated_at'] = invoice_details['updated_at'].strftime(DATE_FORMAT)  # noqa

    assert data == [invoice_details]
示例#8
0
def preview(request):

    #Todo SELECT DISTINCT member from Usage where factNumber is null
    choice_member = Member.objects.exclude(usage=None)

    if not request.POST:
        return render(request, 'invoice.html',
                      {'choice_member': choice_member})

    else:
        member_id = request.POST['member_id']

        invoice_number_max = Invoice.objects.all().aggregate(
            Max('invoice_number'))['invoice_number__max']
        invoice_number = invoice_number_max + 1

        member = Member.objects.get(pk=member_id)
        usages = Usage.objects.filter(member=member, valid=True, invoice=None)

        total_amount = usages.aggregate(total=Sum('total_price'))['total'] or 0

        usages_annotated = usages.values(
            'resource__name', 'resource__unit__name', 'unit_price',
            'project__name').annotate(
                qty=Sum('qty'),
                total_price=Sum('total_price')).order_by('project__name')

        # information about machine hours for animators
        amount_machine_before = AccountEntry.objects.filter(
            member=member).aggregate(total=Sum('amount_machine'))['total'] or 0
        amount_machine_usages = usages.filter(
            resource__payable_by_animation_hours=True).aggregate(
                total=Sum('total_price'))['total'] or 0

        deduction = min(amount_machine_before, amount_machine_usages)

        amount_machine_after = amount_machine_before - deduction

        amount_due = total_amount - deduction

        invoice = Invoice(amount=total_amount,
                          amount_deduction=deduction,
                          amount_due=amount_due,
                          member=member,
                          invoice_number=invoice_number)

        print(total_amount)

        return render(
            request, 'invoice.html', {
                'usages': usages,
                'usages_anotated': usages_annotated,
                'member_info': member,
                'choice_member': choice_member,
                'invoice': invoice,
                'amount_machine_before': amount_machine_before,
                'amount_machine_after': amount_machine_after,
                'amount_machine_usages': amount_machine_usages
            })
示例#9
0
文件: tests.py 项目: tcpr1/vosae-app
    def setUpClass(cls):
        from contacts.models import Organization
        from invoicing.models import Invoice, Currency
        from notification import models as notification_models
        super(NotificationResourceTest, cls).setUpClass()

        cls.payload_kwargs = {
            'data': {},
            'HTTP_X_TENANT': settings.TENANT.slug
        }

        # Retrieve currency which will be referenced
        eur = Currency.objects.get(symbol='EUR')

        # Create an organization which will be referenced
        organization = Organization.objects.create(tenant=settings.TENANT,
                                                   creator=settings.VOSAE_USER,
                                                   corporate_name="My Company",
                                                   private=False)

        # Create deps documents
        invoice = Invoice(tenant=settings.TENANT,
                          account_type='RECEIVABLE',
                          issuer=settings.VOSAE_USER)
        invoice.current_revision.currency = eur.get_snapshot()
        invoice.current_revision.organization = organization
        invoice.save()

        # Create a notification
        notification = notification_models.InvoiceChangedState()
        notification.previous_state = "DRAFT"
        notification.new_state = "REGISTERED"
        notification.issuer = settings.VOSAE_USER
        notification.recipient = settings.VOSAE_USER
        notification.tenant = settings.TENANT
        notification.invoice = invoice
        notification.save()

        cls.cached_data = {
            'invoice_uri':
            cls.resourceDetailURI('invoice', unicode(invoice.id)),
            'notification_uri':
            cls.resourceDetailURI('notification', unicode(notification.id))
        }
        cls.created_documents = [organization, notification, invoice]
示例#10
0
    def setUpClass(cls):
        from contacts.models import Organization
        from invoicing.models import Invoice, Currency
        from notification import models as notification_models
        super(NotificationResourceTest, cls).setUpClass()

        cls.payload_kwargs = {
            'data': {},
            'HTTP_X_TENANT': settings.TENANT.slug
        }

        # Retrieve currency which will be referenced
        eur = Currency.objects.get(symbol='EUR')

        # Create an organization which will be referenced
        organization = Organization.objects.create(tenant=settings.TENANT, creator=settings.VOSAE_USER, corporate_name="My Company", private=False)

        # Create deps documents
        invoice = Invoice(
            tenant=settings.TENANT,
            account_type='RECEIVABLE',
            issuer=settings.VOSAE_USER
        )
        invoice.current_revision.currency = eur.get_snapshot()
        invoice.current_revision.organization = organization
        invoice.save()

        # Create a notification
        notification = notification_models.InvoiceChangedState()
        notification.previous_state = "DRAFT"
        notification.new_state = "REGISTERED"
        notification.issuer = settings.VOSAE_USER
        notification.recipient = settings.VOSAE_USER
        notification.tenant = settings.TENANT
        notification.invoice = invoice
        notification.save()

        cls.cached_data = {
            'invoice_uri': cls.resourceDetailURI('invoice', unicode(invoice.id)),
            'notification_uri': cls.resourceDetailURI('notification', unicode(notification.id))
        }
        cls.created_documents = [organization, notification, invoice]
示例#11
0
 def collection_post(self):
     try:
         invoice = self.request.json
         date_str = invoice.get('date')
         invoice['date'] = parser.parse(date_str)
         DBSession.add(Invoice.from_json(invoice))
         invoice['date'] = date_str
         self.request.response.status_code = 201
         return invoice
     except Exception as e:
         return {'error': str(e)}
示例#12
0
    def test_invoiced_true(self):
        unit = ResourceUnit(name="heure")
        resource = Resource(name="Laser",
                            slug="laser",
                            unit=unit,
                            price_not_member=2,
                            price_member=1)
        usage = Usage(resource=resource, qty=5)

        invoice = Invoice(invoice_number=100, amount=50)
        usage.invoice = invoice

        self.assertTrue(usage.invoiced())
示例#13
0
    def forwards(self, orm):
        # Quotation
        for quotation in Quotation.objects():
            quotation._changed_fields = [
                'tenant', 'issuer', 'organization', 'contact', 'attachments',
                'related_invoice', 'down_payments', 'subscribers'
            ]
            set_embedded_changed_fields(quotation)
            quotation.save()

        # Invoice
        for invoice in Invoice.objects():
            invoice._changed_fields = [
                'tenant', 'issuer', 'organization', 'contact', 'attachments',
                'related_quotation', 'payments', 'subscribers'
            ]
            set_embedded_changed_fields(invoice)
            invoice.save()

        # DownPaymentInvoice
        for down_payment_invoice in DownPaymentInvoice.objects():
            down_payment_invoice._changed_fields = [
                'tenant', 'issuer', 'organization', 'contact', 'attachments',
                'related_quotation', 'payments', 'tax_applied', 'subscribers'
            ]
            set_embedded_changed_fields(down_payment_invoice)
            down_payment_invoice.save()

        # CreditNote
        for credit_note in CreditNote.objects():
            credit_note._changed_fields = [
                'tenant', 'issuer', 'organization', 'contact', 'attachments',
                'related_invoice', 'subscribers'
            ]
            set_embedded_changed_fields(credit_note)
            credit_note.save()

        # Item
        for item in Item.objects():
            item._changed_fields = ['tenant', 'currency', 'tax']
            item.save()

        # Payment
        for payment in Payment.objects():
            payment._changed_fields = ['tenant', 'issuer', 'currency']
            payment.save()

        # Tax
        for tax in Tax.objects():
            tax._changed_fields = ['tenant']
            tax.save()
示例#14
0
def test_pay_invoice(client):
    with db.connection() as DB:
        invoice = Invoice(amount=5, description='Test invoice')
        DB.add(invoice)

    request_data = {'amount': 5}

    response = client.post('/invoices/{0}/pay/'.format(invoice.id),
                           json=request_data)
    data = response.json

    print(data)

    assert data['amount_remaining'] == 0
    assert data['status'] == 'Paid'
    def forwards(self, orm):
        # Quotation
        for quotation in Quotation.objects():
            quotation._changed_fields = ['tenant', 'issuer', 'organization', 'contact', 'attachments', 'related_invoice', 'down_payments', 'subscribers']
            set_embedded_changed_fields(quotation)
            quotation.save()

        # Invoice
        for invoice in Invoice.objects():
            invoice._changed_fields = ['tenant', 'issuer', 'organization', 'contact', 'attachments', 'related_quotation', 'payments', 'subscribers']
            set_embedded_changed_fields(invoice)
            invoice.save()

        # DownPaymentInvoice
        for down_payment_invoice in DownPaymentInvoice.objects():
            down_payment_invoice._changed_fields = ['tenant', 'issuer', 'organization', 'contact', 'attachments', 'related_quotation', 'payments', 'tax_applied', 'subscribers']
            set_embedded_changed_fields(down_payment_invoice)
            down_payment_invoice.save()

        # CreditNote
        for credit_note in CreditNote.objects():
            credit_note._changed_fields = ['tenant', 'issuer', 'organization', 'contact', 'attachments', 'related_invoice', 'subscribers']
            set_embedded_changed_fields(credit_note)
            credit_note.save()

        # Item
        for item in Item.objects():
            item._changed_fields = ['tenant', 'currency', 'tax']
            item.save()

        # Payment
        for payment in Payment.objects():
            payment._changed_fields = ['tenant', 'issuer', 'currency']
            payment.save()

        # Tax
        for tax in Tax.objects():
            tax._changed_fields = ['tenant']
            tax.save()
示例#16
0
def prepare(request, create=False):
    member_id = request.POST['member_id']

    invoice_number_max = Invoice.objects.all().aggregate(Max('invoice_number'))['invoice_number__max'] or 0
    invoice_number = invoice_number_max + 1

    member = Member.objects.get(pk=member_id)
    usages = Usage.objects.filter(member=member, valid=True, invoice=None)

    total_amount = usages.aggregate(total=Sum('total_price'))['total'] or 0

    usages_annotated = usages.values('resource__name',
                                     'resource__unit__name',
                                     'unit_price',
                                     'project__name').annotate(qty=Sum('qty'), total_price=Sum('total_price')
                                                               ).order_by('project__name')

    balance = AccountEntry.objects.filter(member=member).aggregate(machine=Sum('amount_machine'),
                                                                   cash=Sum('amount_cash'))

    print(balance)
    # information about machine hours balance
    amount_machine_before = balance['machine'] or 0
    amount_machine_usages = usages.filter(resource__payable_by_animation_hours=True).aggregate(
        total=Sum('total_price'))['total'] or 0

    deduction_machine = min(amount_machine_before, amount_machine_usages)
    amount_machine_after = amount_machine_before - deduction_machine

    # information about cash balance
    cash_before = balance['cash'] or 0
    remaining_amount = total_amount - deduction_machine
    deduction_cash = min(cash_before, remaining_amount)
    cash_after = cash_before - deduction_cash

    deduction = deduction_machine + deduction_cash

    invoice = Invoice(amount=total_amount,
                      amount_deduction=deduction,
                      member=member,
                      invoice_number=invoice_number)

    print(total_amount)
    if create:
        invoice.save()
        if deduction > 0:
            AccountEntry.objects.create(member=member, amount_machine=-deduction_machine, amount_cash=-deduction_cash, invoice=invoice)

        usages.update(invoice=invoice)
        usages = Usage.objects.filter(invoice=invoice)

    return {'usages': usages,
            'usages_anotated': usages_annotated,
            'member_info': member,
            'invoice': invoice,
            'amount_machine_before': amount_machine_before,
            'amount_machine_after': amount_machine_after,
            'amount_machine_usages': amount_machine_usages,
            'deduction_machine': deduction_machine,
            'cash_before': cash_before,
            'cash_after': cash_after,
            'deduction_cash': deduction_cash
            }
示例#17
0
def generate_child_invoice(**kwargs):
    """
    function to generate a new child invoice based upon the parent
    """
    try:
        parent = Invoice.objects.get(
            invoice_number=kwargs['args'])  # invoice instance
        child = Invoice()
        child.client = parent.client
        child.tax = parent.tax
        child.discount_rate = parent.discount_rate
        child.issued_by = parent.issued_by
        child.invoice_status = Invoice.INVOICE_STATUS[1][0]
        child.recurring = Invoice.RECURRING[0][0]
        child.parent_invoice = parent
        child.date_due = timezone.now().date()
        child.save()
        # save the new m2m intermediary model
        parent_units = Units.objects.filter(invoice=parent)
        for item in parent_units.iterator():
            new = Units()
            new.invoice = child
            new.item = item.item
            new.quantity = item.quantity
            new.save()
        # generate pdf and send email (note: email=False, as already being dispatched due to creation of new PDF)
        invoicing_view.pdf_gen_or_fetch_or_email(
            invoice_number=child.invoice_number,
            type=invoicing_view.PDF_TYPES.get('invoice'),
            email=False,
            regenerate=False)
        return True
    except Invoice.DoesNotExist:
        return None
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()
示例#19
0
文件: tasks.py 项目: zwidny/vosae-app
def update_invoices_states():
    from invoicing.models import Quotation, Invoice
    Quotation.manage_states()
    Invoice.manage_states()
示例#20
0
文件: tasks.py 项目: tcpr1/vosae-app
def update_invoices_states():
    from invoicing.models import Quotation, Invoice
    Quotation.manage_states()
    Invoice.manage_states()