check in billing system models, admin, and sample data generator
diff --git a/planetstack/core/admin.py b/planetstack/core/admin.py
index 713dfdd..8cd54b2 100644
--- a/planetstack/core/admin.py
+++ b/planetstack/core/admin.py
@@ -902,6 +902,72 @@
request.session['auth'] = auth
user_logged_in.connect(cache_credentials)
+class InvoiceInline(admin.TabularInline):
+ model = Invoice
+ extra = 1
+ verbose_name_plural = "Invoices"
+ verbose_name = "Invoice"
+ exclude = ['enacted']
+ fields = ["date", "amount"]
+ readonly_fields = ["date", "amount"]
+ suit_classes = 'suit-tab suit-tab-accountinvoice'
+
+class InvoiceChargeInline(admin.TabularInline):
+ model = Charge
+ extra = 1
+ verbose_name_plural = "Charges"
+ verbose_name = "Charge"
+ exclude = ['enacted']
+ readonly_fields = ["date", "kind", "state", "object", "coreHours", "amount", "slice"]
+
+class InvoiceAdmin(admin.ModelAdmin):
+ list_display = ("date", "account")
+
+ inlines = [InvoiceChargeInline]
+
+ fields = ["date", "account", "amount"]
+ readonly_fields = ["date", "account", "amount"]
+
+class PendingChargeInline(admin.TabularInline):
+ model = Charge
+ extra = 1
+ verbose_name_plural = "Charges"
+ verbose_name = "Charge"
+ exclude = ['enacted', "invoice"]
+ readonly_fields = ["date", "kind", "state", "object", "coreHours", "amount", "slice"]
+ suit_classes = 'suit-tab suit-tab-accountpendingcharges'
+
+ def queryset(self, request):
+ qs = super(PendingChargeInline, self).queryset(request)
+ qs = qs.filter(state="pending")
+ return qs
+
+class PaymentInline(admin.TabularInline):
+ model=Payment
+ extra = 1
+ verbose_name_plural = "Payments"
+ verbose_name = "Payment"
+ exclude = ['enacted']
+ readonly_fields = ["date", "amount"]
+ suit_classes = 'suit-tab suit-tab-accountpayments'
+
+class AccountAdmin(admin.ModelAdmin):
+ list_display = ("site", "balance_due")
+
+ inlines = [InvoiceInline, PaymentInline, PendingChargeInline]
+
+ fieldsets = [
+ (None, {'fields': ['site', 'balance_due', 'total_invoices', 'total_payments']})] # ,'classes':['suit-tab suit-tab-general']}),]
+
+ readonly_fields = ['site', 'balance_due', 'total_invoices', 'total_payments']
+
+ suit_form_tabs =(
+ ('general','Account Details'),
+ ('accountinvoice', 'Invoices'),
+ ('accountpayments', 'Payments'),
+ ('accountpendingcharges','Pending Charges'),
+ )
+
# Now register the new UserAdmin...
admin.site.register(User, UserAdmin)
@@ -919,6 +985,9 @@
# only the top-levels should be displayed
showAll = True
+admin.site.register(Account, AccountAdmin)
+#admin.site.register(Invoice, InvoiceAdmin)
+
admin.site.register(Deployment, DeploymentAdmin)
admin.site.register(Site, SiteAdmin)
admin.site.register(Slice, SliceAdmin)
diff --git a/planetstack/core/models/__init__.py b/planetstack/core/models/__init__.py
index ac12370..b453a14 100644
--- a/planetstack/core/models/__init__.py
+++ b/planetstack/core/models/__init__.py
@@ -28,3 +28,4 @@
from .reservation import ReservedResource
from .reservation import Reservation
from .network import Network, NetworkParameterType, NetworkParameter, NetworkSliver, NetworkTemplate, Router, NetworkSlice
+from .billing import Account, Invoice, Charge, UsableObject, Payment
diff --git a/planetstack/core/models/billing.py b/planetstack/core/models/billing.py
new file mode 100644
index 0000000..6d1c331
--- /dev/null
+++ b/planetstack/core/models/billing.py
@@ -0,0 +1,76 @@
+import datetime
+import os
+import socket
+from django.db import models
+from core.models import PlCoreBase, Site, Slice, Sliver, Deployment
+from django.contrib.contenttypes.models import ContentType
+from django.contrib.contenttypes import generic
+from django.db.models import Sum
+
+class Account(PlCoreBase):
+ site = models.ForeignKey(Site, related_name="accounts", help_text="Site for this account")
+
+ @property
+ def total_invoices(self):
+ # Since the amount of an invoice is the sum of it's charges, we can
+ # compute the sum of the invoices by summing all charges where
+ # charge.invoice != Null.
+ x=self.charges.filter(invoice__isnull=False).aggregate(Sum('amount'))["amount__sum"]
+ if (x==None):
+ return 0.0
+ return x
+
+ @property
+ def total_payments(self):
+ x=self.payments.all().aggregate(Sum('amount'))["amount__sum"]
+ if (x==None):
+ return 0.0
+ return x
+
+ @property
+ def balance_due(self):
+ return self.total_invoices - self.total_payments
+
+ def __unicode__(self): return u'%s' % (self.site.name)
+
+class Invoice(PlCoreBase):
+ date = models.DateTimeField()
+ account = models.ForeignKey(Account, related_name="invoices")
+
+ @property
+ def amount(self):
+ return str(self.charges.all().aggregate(Sum('amount'))["amount__sum"])
+
+ def __unicode__(self): return u'%s-%s' % (self.account.site.name, str(self.date))
+
+class UsableObject(PlCoreBase):
+ name = models.CharField(max_length=1024)
+
+ def __unicode__(self): return u'%s' % (self.name)
+
+class Payment(PlCoreBase):
+ account = models.ForeignKey(Account, related_name="payments")
+ amount = models.FloatField(default=0.0)
+ date = models.DateTimeField(default=datetime.datetime.now)
+
+ def __unicode__(self): return u'%s-%0.2f-%s' % (self.account.site.name, self.amount, str(self.date))
+
+class Charge(PlCoreBase):
+ KIND_CHOICES = (('besteffort', 'besteffort'), ('reservation', 'reservation'), ('monthlyfee', 'monthlyfee'))
+ STATE_CHOICES = (('pending', 'pending'), ('invoiced', 'invoiced'))
+
+ account = models.ForeignKey(Account, related_name="charges")
+ slice = models.ForeignKey(Slice, related_name="charges", null=True, blank=True)
+ kind = models.CharField(max_length=30, choices=KIND_CHOICES, default="besteffort")
+ state = models.CharField(max_length=30, choices=STATE_CHOICES, default="pending")
+ date = models.DateTimeField()
+ object = models.ForeignKey(UsableObject)
+ amount = models.FloatField(default=0.0)
+ coreHours = models.FloatField(default=0.0)
+ invoice = models.ForeignKey(Invoice, blank=True, null=True, related_name="charges")
+
+ def __unicode__(self): return u'%s-%0.2f-%s' % (self.account.site.name, self.amount, str(self.date))
+
+
+
+