From 0f951dcf029d4af284467543a3afdf5bf6581a20 Mon Sep 17 00:00:00 2001 From: Matthew Lemon Date: Tue, 23 Apr 2024 11:16:38 +0100 Subject: switched to Django --- instruments/__init__.py | 0 instruments/admin.py | 11 +++++ instruments/apps.py | 6 +++ instruments/migrations/0001_initial.py | 50 +++++++++++++++++++ instruments/migrations/0002_subinstrument_short.py | 17 +++++++ instruments/migrations/__init__.py | 0 instruments/models.py | 56 ++++++++++++++++++++++ instruments/tests/__init__.py | 0 instruments/tests/test_models.py | 46 ++++++++++++++++++ instruments/views.py | 3 ++ 10 files changed, 189 insertions(+) create mode 100644 instruments/__init__.py create mode 100644 instruments/admin.py create mode 100644 instruments/apps.py create mode 100644 instruments/migrations/0001_initial.py create mode 100644 instruments/migrations/0002_subinstrument_short.py create mode 100644 instruments/migrations/__init__.py create mode 100644 instruments/models.py create mode 100644 instruments/tests/__init__.py create mode 100644 instruments/tests/test_models.py create mode 100644 instruments/views.py (limited to 'instruments') diff --git a/instruments/__init__.py b/instruments/__init__.py new file mode 100644 index 0000000..e69de29 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 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 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. -- cgit v1.2.3