Browse Source

Add document notion

To separate by month/services set
Jocelyn Delande 9 years ago
parent
commit
546d897c86

+ 27 - 3
costs/admin.py

@@ -1,6 +1,11 @@
 from django.contrib import admin
 from django.contrib import admin
 
 
-from .models import Cost, Good, Service, CostUse, GoodUse
+from .models import Cost, Good, Service, CostUse, GoodUse, Document
+
+
+@admin.register(Document)
+class DocumentAdmin(admin.ModelAdmin):
+    list_display = ('name', 'date', 'type')
 
 
 
 
 class GoodUseInline(admin.TabularInline):
 class GoodUseInline(admin.TabularInline):
@@ -13,9 +18,27 @@ class CostUseInline(admin.TabularInline):
     extra = 1
     extra = 1
 
 
 
 
+class DirectDocumentFilter(admin.SimpleListFilter):
+    title = 'Document'
+
+    parameter_name = 'document'
+
+    def queryset(self, request, queryset):
+        document = self.value()
+        if not document:
+            return queryset
+        else:
+            return queryset.filter(document=document)
+
+    def lookups(self, request, model_admin):
+        for i in Document.objects.all():
+            yield i.pk, str(i)
+
+
 @admin.register(Cost)
 @admin.register(Cost)
 class CostAdmin(admin.ModelAdmin):
 class CostAdmin(admin.ModelAdmin):
-    list_display = ('name', 'price')
+    list_display = ('name', 'price', 'document')
+    list_filter = [DirectDocumentFilter]
 
 
 
 
 @admin.register(Good)
 @admin.register(Good)
@@ -23,10 +46,11 @@ class GoodAdmin(admin.ModelAdmin):
     list_display = (
     list_display = (
         '__str__', 'price', 'document',
         '__str__', 'price', 'document',
         'provisioning_duration', 'monthly_provision')
         'provisioning_duration', 'monthly_provision')
+
     list_filter = [DirectDocumentFilter]
     list_filter = [DirectDocumentFilter]
 
 
 
 
 @admin.register(Service)
 @admin.register(Service)
 class ServiceAdmin(admin.ModelAdmin):
 class ServiceAdmin(admin.ModelAdmin):
-    list_display = ('name', 'subscriptions_count')
+    list_display = ('name', 'subscriptions_count', 'document')
     inlines = (CostUseInline, GoodUseInline)
     inlines = (CostUseInline, GoodUseInline)

+ 29 - 0
costs/migrations/0004_auto_20151129_2340.py

@@ -0,0 +1,29 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('costs', '0003_auto_20151128_1044'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Document',
+            fields=[
+                ('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)),
+                ('name', models.CharField(max_length=130)),
+                ('comment', models.TextField(blank=True)),
+                ('date', models.DateField(auto_now_add=True)),
+                ('type', models.CharField(choices=[('fact', 'relevé'), ('plan', 'scénario/estimation')], max_length='10')),
+            ],
+        ),
+        migrations.AlterField(
+            model_name='service',
+            name='subscriptions_count',
+            field=models.PositiveIntegerField(default=0),
+        ),
+    ]

+ 31 - 0
costs/migrations/0005_auto_20151129_2354.py

@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('costs', '0004_auto_20151129_2340'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='cost',
+            name='document',
+            field=models.ForeignKey(to='costs.Document', default=1),
+            preserve_default=False,
+        ),
+        migrations.AddField(
+            model_name='good',
+            name='document',
+            field=models.ForeignKey(to='costs.Document', default=1),
+            preserve_default=False,
+        ),
+        migrations.AlterField(
+            model_name='document',
+            name='type',
+            field=models.CharField(choices=[('fact', 'relevé'), ('plan', 'scénario/estimation')], max_length=10),
+        ),
+    ]

+ 37 - 2
costs/models.py

@@ -6,6 +6,24 @@ from django.db import models
 from .validators import less_than_one
 from .validators import less_than_one
 
 
 
 
+class Document(models.Model):
+    """ A document is a scenario or a record from facts, on 1 month.
+    """
+    TYPE_FACT = 'fact'
+    TYPE_PLAN = 'plan'
+
+    name = models.CharField(max_length=130)
+    comment = models.TextField(blank=True)
+    date = models.DateField(auto_now_add=True)
+    type = models.CharField(max_length=10, choices=(
+        (TYPE_FACT, 'relevé'),
+        (TYPE_PLAN, 'scénario/estimation'),
+    ))
+
+    def __str__(self):
+        return '{} {:%b %Y}'.format(self.name, self.date)
+
+
 class AbstractItem(models.Model):
 class AbstractItem(models.Model):
     name = models.CharField(max_length=130)
     name = models.CharField(max_length=130)
     description = models.TextField(blank=True)
     description = models.TextField(blank=True)
@@ -36,7 +54,16 @@ class AbstractItem(models.Model):
         abstract = True
         abstract = True
 
 
 
 
-class Cost(AbstractItem):
+class AbstractCostingItem(AbstractItem):
+    """ A costing item, linked to a document
+    """
+    document = models.ForeignKey(Document)
+
+    class Meta:
+        abstract = True
+
+
+class Cost(AbstractCostingItem):
     """ A monthtly cost we have to pay
     """ A monthtly cost we have to pay
     """
     """
     price = models.FloatField(help_text="Coût mensuel")
     price = models.FloatField(help_text="Coût mensuel")
@@ -48,7 +75,7 @@ class Cost(AbstractItem):
         verbose_name = 'Coût'
         verbose_name = 'Coût'
 
 
 
 
-class Good(AbstractItem):
+class Good(AbstractCostingItem):
     """ A good, which replacement is provisioned
     """ A good, which replacement is provisioned
     """
     """
     price = models.FloatField()
     price = models.FloatField()
@@ -127,3 +154,11 @@ class Service(AbstractItem):
 
 
     def get_absolute_url(self):
     def get_absolute_url(self):
         return reverse('detail-service', kwargs={'pk': self.pk})
         return reverse('detail-service', kwargs={'pk': self.pk})
+
+    def document(self):
+        if self.costs.exists():
+            return self.costs.first().document
+        elif self.goods.exists():
+            return self.costs.first().document
+        else:
+            return None

+ 3 - 2
costs/tests/test_models.py

@@ -1,20 +1,21 @@
 from django.test import TestCase
 from django.test import TestCase
 from django.core.exceptions import ValidationError
 from django.core.exceptions import ValidationError
 
 
-from ..models import Service, Cost, CostUse
+from ..models import Service, Cost, CostUse, Document
 
 
 
 
 class AbstractUseTests(TestCase):
 class AbstractUseTests(TestCase):
     """ Testing AbstractUseTests through CostUse
     """ Testing AbstractUseTests through CostUse
     """
     """
     def setUp(self):
     def setUp(self):
+        self.doc = Document.objects.create(name='budget')
         self.hosting_service = Service.objects.create(
         self.hosting_service = Service.objects.create(
             name='Physical hosting')
             name='Physical hosting')
         self.mailbox_service = Service.objects.create(
         self.mailbox_service = Service.objects.create(
             name='Mailbox')
             name='Mailbox')
 
 
         self.datacenter_cost = Cost.objects.create(
         self.datacenter_cost = Cost.objects.create(
-            name='Datacenter', price=100)
+            name='Datacenter', price=100, document=self.doc)
 
 
     def test_can_add_service_share(self):
     def test_can_add_service_share(self):
         use = CostUse(
         use = CostUse(

+ 4 - 2
costs/tests/test_views.py

@@ -2,16 +2,18 @@ import datetime
 
 
 from django.test import TestCase
 from django.test import TestCase
 
 
-from ..models import Cost, Good, Service, GoodUse, CostUse
+from ..models import Cost, Document, Good, Service, GoodUse, CostUse
 
 
 
 
 class ViewsTests(TestCase):
 class ViewsTests(TestCase):
     def setUp(self):
     def setUp(self):
-        rent = Cost.objects.create(name='Rent', price=100)
+        self.doc = Document.objects.create(name='budget')
+        rent = Cost.objects.create(name='Rent', price=100, document=self.doc)
         server = Good.objects.create(
         server = Good.objects.create(
             name='Server',
             name='Server',
             price=1000,
             price=1000,
             provisioning_duration=datetime.timedelta(days=36*20.6),
             provisioning_duration=datetime.timedelta(days=36*20.6),
+            document=self.doc,
         )
         )
         vpn = Service.objects.create(name='VPN')
         vpn = Service.objects.create(name='VPN')
         GoodUse.objects.create(resource=server, service=vpn, share=0.5)
         GoodUse.objects.create(resource=server, service=vpn, share=0.5)