Skip to content

Commit 19a0d9b

Browse files
authored
Merge pull request #142 from maykinmedia/feature/103-number-generator
✨ [#103] added nummer generator for all nummer fields
2 parents bf10777 + e5525cd commit 19a0d9b

File tree

11 files changed

+221
-30
lines changed

11 files changed

+221
-30
lines changed

src/openklant/components/klantinteracties/api/tests/test_internetaken.py

+40-7
Original file line numberDiff line numberDiff line change
@@ -54,16 +54,49 @@ def test_create_internetaak(self):
5454

5555
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
5656

57-
data = response.json()
57+
response_data = response.json()
5858

59-
self.assertEqual(data["toegewezenAanActor"]["uuid"], str(actor.uuid))
59+
self.assertEqual(response_data["toegewezenAanActor"]["uuid"], str(actor.uuid))
6060
self.assertEqual(
61-
data["aanleidinggevendKlantcontact"]["uuid"], str(klantcontact.uuid)
61+
response_data["aanleidinggevendKlantcontact"]["uuid"],
62+
str(klantcontact.uuid),
6263
)
63-
self.assertEqual(data["nummer"], "1312312312")
64-
self.assertEqual(data["gevraagdeHandeling"], "gevraagdeHandeling")
65-
self.assertEqual(data["toelichting"], "toelichting")
66-
self.assertEqual(data["status"], "verwerkt")
64+
self.assertEqual(response_data["nummer"], "1312312312")
65+
self.assertEqual(response_data["gevraagdeHandeling"], "gevraagdeHandeling")
66+
self.assertEqual(response_data["toelichting"], "toelichting")
67+
self.assertEqual(response_data["status"], "verwerkt")
68+
69+
with self.subTest("auto_generate_max_nummer_plus_one"):
70+
data["nummer"] = ""
71+
response = self.client.post(list_url, data)
72+
73+
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
74+
response_data = response.json()
75+
self.assertEqual(response_data["nummer"], "1312312313")
76+
77+
with self.subTest("auto_generate_nummer_unique_validation"):
78+
data["nummer"] = "1312312313"
79+
response = self.client.post(list_url, data)
80+
81+
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
82+
response_data = response.json()
83+
self.assertEqual(
84+
response_data["invalidParams"][0]["reason"],
85+
"Er bestaat al een interne taak met eenzelfde nummer.",
86+
)
87+
88+
with self.subTest("auto_generate_nummer_over_10_characters_error_message"):
89+
InterneTaakFactory.create(nummer="9999999999")
90+
data["nummer"] = ""
91+
response = self.client.post(list_url, data)
92+
93+
self.assertEqual(response.status_code, status.HTTP_409_CONFLICT)
94+
response_data = response.json()
95+
self.assertEqual(
96+
response_data["detail"],
97+
"Er kon niet automatisch een opvolgend nummer worden gegenereerd. "
98+
"Het maximaal aantal tekens is bereikt.",
99+
)
67100

68101
def test_update_internetaak(self):
69102
actor, actor2 = ActorFactory.create_batch(2)

src/openklant/components/klantinteracties/api/tests/test_klantcontacten.py

+32
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,38 @@ def test_create_klantcontact(self):
8585
],
8686
)
8787

88+
with self.subTest("auto_generate_max_nummer_plus_one"):
89+
data["nummer"] = ""
90+
response = self.client.post(list_url, data)
91+
92+
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
93+
response_data = response.json()
94+
self.assertEqual(response_data["nummer"], "1234567891")
95+
96+
with self.subTest("auto_generate_nummer_unique_validation"):
97+
data["nummer"] = "1234567891"
98+
response = self.client.post(list_url, data)
99+
100+
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
101+
response_data = response.json()
102+
self.assertEqual(
103+
response_data["invalidParams"][0]["reason"],
104+
"Er bestaat al een klantcontact met eenzelfde nummer.",
105+
)
106+
107+
with self.subTest("auto_generate_nummer_over_10_characters_error_message"):
108+
KlantcontactFactory.create(nummer="9999999999")
109+
data["nummer"] = ""
110+
response = self.client.post(list_url, data)
111+
112+
self.assertEqual(response.status_code, status.HTTP_409_CONFLICT)
113+
response_data = response.json()
114+
self.assertEqual(
115+
response_data["detail"],
116+
"Er kon niet automatisch een opvolgend nummer worden gegenereerd. "
117+
"Het maximaal aantal tekens is bereikt.",
118+
)
119+
88120
def test_create_klantcontact_with_reverse_lookup_fields(self):
89121
actor, actor2 = ActorFactory.create_batch(2)
90122
list_url = reverse("klantinteracties:klantcontact-list")

src/openklant/components/klantinteracties/api/tests/test_partijen.py

+52-18
Original file line numberDiff line numberDiff line change
@@ -126,24 +126,8 @@ def test_create_partij(self):
126126
},
127127
)
128128

129-
with self.subTest("voorkeurs_adres_must_be_given_digitaal_adres_validation"):
130-
data["voorkeursDigitaalAdres"] = {"uuid": str(digitaal_adres2.uuid)}
131-
response = self.client.post(list_url, data)
132-
133-
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
134-
response_data = response.json()
135-
self.assertEqual(
136-
response_data["invalidParams"],
137-
[
138-
{
139-
"name": "voorkeursDigitaalAdres",
140-
"code": "invalid",
141-
"reason": "Het voorkeurs adres moet een gelinkte digitaal adres zijn.",
142-
}
143-
],
144-
)
145-
146129
with self.subTest("create_partij_without_foreignkey_relations"):
130+
data["nummer"] = "1298329192"
147131
data["digitaleAdressen"] = []
148132
data["voorkeursDigitaalAdres"] = None
149133
data["vertegenwoordigde"] = []
@@ -154,7 +138,7 @@ def test_create_partij(self):
154138

155139
response_data = response.json()
156140

157-
self.assertEqual(response_data["nummer"], "1298329191")
141+
self.assertEqual(response_data["nummer"], "1298329192")
158142
self.assertEqual(response_data["interneNotitie"], "interneNotitie")
159143
self.assertEqual(response_data["digitaleAdressen"], [])
160144
self.assertIsNone(response_data["voorkeursDigitaalAdres"])
@@ -196,6 +180,56 @@ def test_create_partij(self):
196180
},
197181
)
198182

183+
with self.subTest("auto_generate_max_nummer_plus_one"):
184+
data["nummer"] = ""
185+
response = self.client.post(list_url, data)
186+
187+
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
188+
response_data = response.json()
189+
self.assertEqual(response_data["nummer"], "1298329193")
190+
191+
with self.subTest("auto_generate_nummer_unique_validation"):
192+
data["nummer"] = "1298329193"
193+
response = self.client.post(list_url, data)
194+
195+
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
196+
response_data = response.json()
197+
self.assertEqual(
198+
response_data["invalidParams"][0]["reason"],
199+
"Er bestaat al een partij met eenzelfde nummer.",
200+
)
201+
202+
with self.subTest("auto_generate_nummer_over_10_characters_error_message"):
203+
PartijFactory.create(nummer="9999999999")
204+
data["nummer"] = ""
205+
response = self.client.post(list_url, data)
206+
207+
self.assertEqual(response.status_code, status.HTTP_409_CONFLICT)
208+
response_data = response.json()
209+
self.assertEqual(
210+
response_data["detail"],
211+
"Er kon niet automatisch een opvolgend nummer worden gegenereerd. "
212+
"Het maximaal aantal tekens is bereikt.",
213+
)
214+
215+
with self.subTest("voorkeurs_adres_must_be_given_digitaal_adres_validation"):
216+
data["nummer"] = "1298329194"
217+
data["voorkeursDigitaalAdres"] = {"uuid": str(digitaal_adres2.uuid)}
218+
response = self.client.post(list_url, data)
219+
220+
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
221+
response_data = response.json()
222+
self.assertEqual(
223+
response_data["invalidParams"],
224+
[
225+
{
226+
"name": "voorkeursDigitaalAdres",
227+
"code": "invalid",
228+
"reason": "Het voorkeurs adres moet een gelinkte digitaal adres zijn.",
229+
}
230+
],
231+
)
232+
199233
def test_create_persoon(self):
200234
list_url = reverse("klantinteracties:partij-list")
201235
data = {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Generated by Django 3.2.23 on 2024-01-16 15:41
2+
3+
import django.core.validators
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
dependencies = [
9+
("klantinteracties", "0007_auto_20231201_1601"),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name="internetaak",
15+
name="nummer",
16+
field=models.CharField(
17+
blank=True,
18+
help_text="Uniek identificerend nummer dat tijdens communicatie tussen mensen kan worden gebruikt om de specifieke interne taak aan te duiden.",
19+
max_length=10,
20+
unique=True,
21+
validators=[django.core.validators.validate_integer],
22+
verbose_name="nummer",
23+
),
24+
),
25+
migrations.AlterField(
26+
model_name="klantcontact",
27+
name="nummer",
28+
field=models.CharField(
29+
blank=True,
30+
help_text="Uniek identificerend nummer dat tijdens communicatie tussen mensen kan worden gebruikt om het specifieke klantcontact aan te duiden.",
31+
max_length=10,
32+
unique=True,
33+
validators=[django.core.validators.validate_integer],
34+
verbose_name="nummer",
35+
),
36+
),
37+
migrations.AlterField(
38+
model_name="partij",
39+
name="nummer",
40+
field=models.CharField(
41+
blank=True,
42+
help_text="Uniek identificerend nummer dat tijdens communicatie tussen mensen kan worden gebruikt om de specifieke partij aan te duiden.",
43+
max_length=10,
44+
unique=True,
45+
validators=[django.core.validators.validate_integer],
46+
verbose_name="nummer",
47+
),
48+
),
49+
]

src/openklant/components/klantinteracties/models/internetaken.py

+8
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
from django.db import models
55
from django.utils.translation import gettext_lazy as _
66

7+
from openklant.components.utils.number_generator import number_generator
8+
79
from .actoren import Actor
810
from .constants import Taakstatus
911
from .klantcontacten import Klantcontact
@@ -37,6 +39,8 @@ class InterneTaak(models.Model):
3739
),
3840
validators=[validate_integer],
3941
max_length=10,
42+
unique=True,
43+
blank=True,
4044
)
4145
gevraagde_handeling = models.CharField(
4246
_("gevraagde handeling"),
@@ -71,3 +75,7 @@ class InterneTaak(models.Model):
7175
class Meta:
7276
verbose_name = _("interne taak")
7377
verbose_name_plural = _("interne taken")
78+
79+
def save(self, *args, **kwargs):
80+
number_generator(self, InterneTaak)
81+
return super().save(*args, **kwargs)

src/openklant/components/klantinteracties/models/klantcontacten.py

+7
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from django.utils.translation import gettext_lazy as _
77

88
from openklant.components.utils.mixins import APIMixin
9+
from openklant.components.utils.number_generator import number_generator
910

1011
from .actoren import Actor
1112
from .constants import Klantcontrol
@@ -42,6 +43,8 @@ class Klantcontact(APIMixin, models.Model):
4243
),
4344
validators=[validate_integer],
4445
max_length=10,
46+
unique=True,
47+
blank=True,
4548
)
4649
kanaal = models.CharField(
4750
_("kanaal"),
@@ -100,6 +103,10 @@ class Meta:
100103
verbose_name = _("klantcontact")
101104
verbose_name_plural = _("klantcontacten")
102105

106+
def save(self, *args, **kwargs):
107+
number_generator(self, Klantcontact)
108+
return super().save(*args, **kwargs)
109+
103110
def __str__(self):
104111
return self.nummer
105112

src/openklant/components/klantinteracties/models/partijen.py

+7
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from vng_api_common.descriptors import GegevensGroepType
99

1010
from openklant.components.utils.mixins import APIMixin
11+
from openklant.components.utils.number_generator import number_generator
1112

1213
from .constants import SoortPartij
1314
from .mixins import BezoekadresMixin, ContactnaamMixin, CorrespondentieadresMixin
@@ -43,6 +44,8 @@ class Partij(APIMixin, BezoekadresMixin, CorrespondentieadresMixin):
4344
),
4445
validators=[validate_integer],
4546
max_length=10,
47+
unique=True,
48+
blank=True,
4649
)
4750
interne_notitie = models.TextField(
4851
_("interne notitie"),
@@ -98,6 +101,10 @@ def clean(self):
98101
_("Het voorkeurs adres moet een gelinkte digitaal adres zijn.")
99102
)
100103

104+
def save(self, *args, **kwargs):
105+
number_generator(self, Partij)
106+
return super().save(*args, **kwargs)
107+
101108

102109
class Organisatie(models.Model):
103110
partij = models.OneToOneField(

src/openklant/components/klantinteracties/models/tests/factories/internetaken.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import random
2-
31
import factory.fuzzy
42

53
from openklant.components.klantinteracties.models.constants import Taakstatus
@@ -16,7 +14,7 @@ class InterneTaakFactory(factory.django.DjangoModelFactory):
1614
uuid = factory.Faker("uuid4")
1715
actor = factory.SubFactory(ActorFactory)
1816
klantcontact = factory.SubFactory(KlantcontactFactory)
19-
nummer = "".join(random.choice("0123456789") for i in range(10))
17+
nummer = factory.Sequence(lambda n: str(n))
2018
gevraagde_handeling = factory.Faker("word")
2119
toelichting = factory.Faker("word")
2220
status = factory.fuzzy.FuzzyChoice(Taakstatus.values)

src/openklant/components/klantinteracties/models/tests/factories/klantcontacten.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
class KlantcontactFactory(factory.django.DjangoModelFactory):
1313
uuid = factory.Faker("uuid4")
14-
nummer = "".join(random.choice("0123456789") for i in range(10))
14+
nummer = factory.Sequence(lambda n: str(n))
1515
kanaal = factory.Faker("word")
1616
onderwerp = factory.Faker("word")
1717
inhoud = factory.Faker("word")

src/openklant/components/klantinteracties/models/tests/factories/partijen.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
class PartijFactory(factory.django.DjangoModelFactory):
2121
uuid = factory.Faker("uuid4")
2222
voorkeurs_digitaal_adres = factory.SubFactory(DigitaalAdresFactory)
23-
nummer = "".join(random.choice("0123456789") for i in range(10))
23+
nummer = factory.Sequence(lambda n: str(n))
2424
soort_partij = factory.fuzzy.FuzzyChoice(SoortPartij.values)
2525
indicatie_geheimhouding = factory.Faker("pybool")
2626
indicatie_actief = factory.Faker("pybool")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from django.db.models import BigIntegerField, Max, Model
2+
from django.db.models.functions import Cast
3+
from django.utils.translation import gettext_lazy as _
4+
5+
from vng_api_common.exceptions import Conflict
6+
7+
8+
def number_generator(self, model: Model) -> None:
9+
if not self.nummer:
10+
max_nummer = (
11+
model.objects.annotate(
12+
nummer_int=Cast("nummer", output_field=BigIntegerField())
13+
).aggregate(Max("nummer_int"))["nummer_int__max"]
14+
or 0
15+
)
16+
self.nummer = str(max_nummer + 1).rjust(10, "0")
17+
if len(self.nummer) > 10:
18+
raise Conflict(
19+
_(
20+
"Er kon niet automatisch een opvolgend nummer worden gegenereerd. "
21+
"Het maximaal aantal tekens is bereikt."
22+
)
23+
)

0 commit comments

Comments
 (0)