From 6e0b23dc3b9f6f044528eb041e1a7ab601afd808 Mon Sep 17 00:00:00 2001
From: Andreas Ellewsen <andreas@ellewsen.no>
Date: Tue, 29 Nov 2022 15:04:05 +0100
Subject: [PATCH] Change unique constraint on OuIdentifiers

OuIdentifiers used to be restricted to the name+value combination to
make sure that no two units could have the same legacy_stedkode. This
becomes problematic when two units have the same short_name.

This makes it possible for two units to have the same value for the same
OuIdentifier name, and adds a constraint that makes it impossible for
each unit to have more than one OuIdentifier with the same 'name', i.e
multiple legacy_stedkode for one unit.
---
 ...ouidentifier_unique_identifier_and_more.py | 50 +++++++++++++++++++
 greg/models.py                                |  4 +-
 greg/utils.py                                 |  5 +-
 3 files changed, 56 insertions(+), 3 deletions(-)
 create mode 100644 greg/migrations/0026_remove_ouidentifier_unique_identifier_and_more.py

diff --git a/greg/migrations/0026_remove_ouidentifier_unique_identifier_and_more.py b/greg/migrations/0026_remove_ouidentifier_unique_identifier_and_more.py
new file mode 100644
index 00000000..6c847854
--- /dev/null
+++ b/greg/migrations/0026_remove_ouidentifier_unique_identifier_and_more.py
@@ -0,0 +1,50 @@
+"""
+This migrations was made necessary due to OrgReg using the same short
+name for multiple OrganizationUnits.
+
+The restriction existed to prevent multiple units having the same
+legacy_stedkode. This should never be the case but this value is not
+used for anything other than clarity when choosing an OrganizationUnit
+from a dropdown in the frontend and should thus be safe.
+"""
+# Generated by Django 4.1.3 on 2022-11-29 11:44
+
+from django.db import migrations, models
+
+
+def cleanup_duplicates(apps, schema_editor):
+    """
+    Keep most recently updated value for each name on each ou
+    """
+    OuIdentifier = apps.get_model("greg", "OuIdentifier")
+    previous = None
+    for oui in OuIdentifier.objects.order_by("name", "orgunit", "updated"):
+        if (
+            previous
+            and oui.name == previous.name
+            and oui.orgunit.id == previous.orgunit.id
+        ):
+            previous.delete()
+        previous = oui
+    return
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("greg", "0025_alter_ouidentifier_source"),
+    ]
+
+    operations = [
+        migrations.RunPython(cleanup_duplicates),
+        migrations.RemoveConstraint(
+            model_name="ouidentifier",
+            name="unique_identifier",
+        ),
+        migrations.AddConstraint(
+            model_name="ouidentifier",
+            constraint=models.UniqueConstraint(
+                fields=("name", "orgunit"), name="unique_identifier"
+            ),
+        ),
+    ]
diff --git a/greg/models.py b/greg/models.py
index af7aabad..5e23a1cc 100644
--- a/greg/models.py
+++ b/greg/models.py
@@ -467,7 +467,9 @@ class OuIdentifier(BaseModel):
 
     class Meta:
         constraints = [
-            models.UniqueConstraint(name="unique_identifier", fields=["name", "value"])
+            models.UniqueConstraint(
+                name="unique_identifier", fields=["name", "orgunit"]
+            )
         ]
 
     def __str__(self) -> str:
diff --git a/greg/utils.py b/greg/utils.py
index 1a2b4ba2..fa61a818 100644
--- a/greg/utils.py
+++ b/greg/utils.py
@@ -1,6 +1,7 @@
 import re
 import typing
-from datetime import date, datetime, timedelta
+from datetime import date, datetime, timedelta, timezone as dt_timezone
+
 from rest_framework import serializers
 from django.db import transaction
 from django.conf import settings
@@ -149,7 +150,7 @@ def _compute_checksum(input_digits: str) -> bool:
 
 def date_to_datetime_midnight(in_date: date) -> datetime:
     """Convert a date object to a datetime object with timezone utc"""
-    return datetime.combine(in_date, datetime.min.time(), tzinfo=timezone.utc)
+    return datetime.combine(in_date, datetime.min.time(), tzinfo=dt_timezone.utc)
 
 
 def str2date(in_date: typing.Union[str, date]):
-- 
GitLab