summaryrefslogtreecommitdiffstats
path: root/instruments
diff options
context:
space:
mode:
authorMatthew Lemon <y@yulqen.org>2024-04-23 11:16:38 +0100
committerMatthew Lemon <y@yulqen.org>2024-04-23 11:16:38 +0100
commit0f951dcf029d4af284467543a3afdf5bf6581a20 (patch)
treea48384210cdc168e3bd3ccff6d6d516eeed9e748 /instruments
parent8b084e9fe7a5f3a04c32daf9a24f7f2cf67300f9 (diff)
switched to Django
Diffstat (limited to 'instruments')
-rw-r--r--instruments/__init__.py0
-rw-r--r--instruments/admin.py11
-rw-r--r--instruments/apps.py6
-rw-r--r--instruments/migrations/0001_initial.py50
-rw-r--r--instruments/migrations/0002_subinstrument_short.py17
-rw-r--r--instruments/migrations/__init__.py0
-rw-r--r--instruments/models.py56
-rw-r--r--instruments/tests/__init__.py0
-rw-r--r--instruments/tests/test_models.py46
-rw-r--r--instruments/views.py3
10 files changed, 189 insertions, 0 deletions
diff --git a/instruments/__init__.py b/instruments/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/instruments/__init__.py
diff --git a/instruments/admin.py b/instruments/admin.py
new file mode 100644
index 0000000..2c55b2c
--- /dev/null
+++ b/instruments/admin.py
@@ -0,0 +1,11 @@
+from django.contrib import admin
+
+from .models import Instrument, SubInstrument
+
+
+class SubInstrumentAdmin(admin.ModelAdmin):
+ list_display = ("__str__", "itype", "parent")
+
+
+admin.site.register(Instrument)
+admin.site.register(SubInstrument, SubInstrumentAdmin)
diff --git a/instruments/apps.py b/instruments/apps.py
new file mode 100644
index 0000000..9aefef2
--- /dev/null
+++ b/instruments/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class InstrumentsConfig(AppConfig):
+ default_auto_field = "django.db.models.BigAutoField"
+ name = "instruments"
diff --git a/instruments/migrations/0001_initial.py b/instruments/migrations/0001_initial.py
new file mode 100644
index 0000000..ef73e3c
--- /dev/null
+++ b/instruments/migrations/0001_initial.py
@@ -0,0 +1,50 @@
+# Generated by Django 4.0.8 on 2022-11-02 09:00
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ('engagements', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Instrument',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('date_created', models.DateTimeField(auto_now_add=True)),
+ ('last_modified', models.DateTimeField(auto_now=True)),
+ ('name', models.CharField(max_length=512)),
+ ('long_title', models.CharField(blank=True, max_length=1024, null=True)),
+ ('designator', models.CharField(blank=True, max_length=3, null=True)),
+ ('link', models.URLField(blank=True, max_length=1024, null=True)),
+ ('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='engagements.organisation')),
+ ],
+ options={
+ 'verbose_name_plural': 'Instruments',
+ },
+ ),
+ migrations.CreateModel(
+ name='SubInstrument',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('date_created', models.DateTimeField(auto_now_add=True)),
+ ('last_modified', models.DateTimeField(auto_now=True)),
+ ('is_guidance', models.BooleanField(blank=True, default=False, null=True)),
+ ('itype', models.CharField(choices=[('DSC', 'Defence Security Condition (DSC)'), ('DSYAP', 'Defence Security Assessment Principle (DSyAP)'), ('DSTAIG', "Defence Security Testing And I Don't Know (DSTAIG)")], max_length=6, verbose_name='Instrument Type')),
+ ('title', models.CharField(max_length=512)),
+ ('description', models.TextField(blank=True, null=True)),
+ ('rationale', models.TextField(blank=True, null=True)),
+ ('parent', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='instruments.instrument', verbose_name='Parent Instrument')),
+ ('relative', models.ManyToManyField(to='instruments.subinstrument')),
+ ],
+ options={
+ 'verbose_name_plural': 'Sub Instruments',
+ },
+ ),
+ ]
diff --git a/instruments/migrations/0002_subinstrument_short.py b/instruments/migrations/0002_subinstrument_short.py
new file mode 100644
index 0000000..6492158
--- /dev/null
+++ b/instruments/migrations/0002_subinstrument_short.py
@@ -0,0 +1,17 @@
+# Generated by Django 4.1.8 on 2023-04-21 08:20
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("instruments", "0001_initial"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="subinstrument",
+ name="short",
+ field=models.CharField(blank=True, max_length=10, null=True),
+ ),
+ ]
diff --git a/instruments/migrations/__init__.py b/instruments/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/instruments/migrations/__init__.py
diff --git a/instruments/models.py b/instruments/models.py
new file mode 100644
index 0000000..e266fb2
--- /dev/null
+++ b/instruments/models.py
@@ -0,0 +1,56 @@
+from django.db import models
+
+from engagements.models import EngagementEffort, Organisation
+
+
+class Common(models.Model):
+ date_created = models.DateTimeField(auto_now_add=True)
+ last_modified = models.DateTimeField(auto_now=True)
+
+ class Meta:
+ abstract = True
+
+
+class Instrument(Common):
+ "JSP 628, JSP 440, the ONR ones, etc"
+ name = models.CharField(max_length=512, null=False, blank=False)
+ long_title = models.CharField(max_length=1024, null=True, blank=True)
+ designator = models.CharField(max_length=3, null=True, blank=True)
+ owner = models.ForeignKey(Organisation, null=False, blank=False, on_delete=models.CASCADE)
+ link = models.URLField(max_length=1024, null=True, blank=True)
+
+ def __str__(self):
+ return self.name
+
+ class Meta:
+ verbose_name_plural = "Instruments"
+
+
+class SubInstrument(Common):
+ "DSCs, Chapters, Supplements, Leaflets..."
+ choices = (
+ ("DSC", "Defence Security Condition (DSC)"),
+ ("DSYAP", "Defence Security Assessment Principle (DSyAP)"),
+ ("DSTAIG", "Defence Security Testing And I Don't Know (DSTAIG)"),
+ )
+ is_guidance = models.BooleanField(null=True, blank=True, default=False)
+ itype = models.CharField(choices=choices, max_length=6, verbose_name="Instrument Type")
+ title = models.CharField(max_length=512, null=False, blank=False)
+ parent = models.ForeignKey(Instrument, on_delete=models.CASCADE, verbose_name="Parent Instrument")
+ description = models.TextField(null=True, blank=True)
+ rationale = models.TextField(null=True, blank=True)
+ relative = models.ManyToManyField("self")
+ short = models.CharField(max_length=10, null=True, blank=True)
+
+ def effort(self):
+ return EngagementEffort.objects.filter(sub_instruments__contains=self)
+
+ def effort_for_org(self, org):
+ eff = EngagementEffort.objects.filter(engagement__external_party=org).filter(effort_type="REGULATION")
+ return sum(e.effort_total_hours() for e in eff)
+
+ def __str__(self):
+ return self.title
+
+ class Meta:
+ verbose_name_plural = "Sub Instruments"
diff --git a/instruments/tests/__init__.py b/instruments/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/instruments/tests/__init__.py
diff --git a/instruments/tests/test_models.py b/instruments/tests/test_models.py
new file mode 100644
index 0000000..0d7eafa
--- /dev/null
+++ b/instruments/tests/test_models.py
@@ -0,0 +1,46 @@
+import datetime
+
+import pytest
+from django.test import TestCase
+
+from engagements import models
+from engagements.utils import populate_database
+
+
+class TestModels(TestCase):
+ @classmethod
+ def setUpTestData(cls):
+ cls.data = populate_database()
+
+ def test_check_all_dcs(self):
+ dscs = self.data.get("sub_instruments")
+ self.assertEqual(dscs[0].title, "DSC 1 - Title 1")
+
+ @pytest.mark.django_db
+ def test_get_hours_of_effort_for_dsc_for_org(self):
+ org = self.data["orgs"][0]
+ et = models.EngagementType.objects.get(name="INSPECTION")
+ si = self.data["sub_instruments"][0]
+ si2 = self.data["sub_instruments"][2]
+ si3 = self.data["sub_instruments"][3]
+ # si_not = self.data["sub_instruments"][1]
+ engagement = models.Engagement.objects.create(
+ proposed_start_date=datetime.date(2022, 10, 10),
+ proposed_end_date=datetime.date(2022, 10, 10),
+ engagement_type=et,
+ external_party=org,
+ )
+ ef1 = models.EngagementEffort.objects.create(
+ is_planned=True,
+ effort_type="REGULATION",
+ proposed_start_date=datetime.datetime(2022, 10, 10, 10, 0),
+ proposed_end_date=datetime.datetime(2022, 10, 10, 12, 0),
+ engagement=engagement,
+ )
+ ef1.sub_instruments.add(si) # DSC 1
+ ef1.sub_instruments.add(si2) # DSC 3
+ ef1.sub_instruments.add(si3) # DSC 4
+ ef1.save()
+ self.assertEqual(si.effort_for_org(org), 2)
+ self.assertEqual(si2.effort_for_org(org), 2)
+ self.assertEqual(si3.effort_for_org(org), 2)
diff --git a/instruments/views.py b/instruments/views.py
new file mode 100644
index 0000000..fd0e044
--- /dev/null
+++ b/instruments/views.py
@@ -0,0 +1,3 @@
+# from django.shortcuts import render
+
+# Create your views here.