Skip to content
This repository has been archived by the owner on Jun 8, 2023. It is now read-only.

Issue/vrz 007 unique validation #13

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion src/verzoeken/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@
)
from verzoeken.sync.signals import SyncError

from .validators import ObjectVerzoekCreateValidator
from .validators import (
KlantProductUniqueTogetherValidator,
ObjectVerzoekCreateValidator,
)

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -227,6 +230,16 @@ class Meta:
],
},
}
validators = [
KlantProductUniqueTogetherValidator(
queryset=VerzoekProduct.objects.all(),
fields=["product", "verzoek"],
),
KlantProductUniqueTogetherValidator(
queryset=VerzoekProduct.objects.all(),
fields=["product_code", "verzoek"],
),
]

def validate(self, attrs):
validated_attrs = super().validate(attrs)
Expand Down
32 changes: 32 additions & 0 deletions src/verzoeken/api/tests/test_verzoekproduct.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,22 @@ def test_create_verzoekproduct_with_invalid_product_url(self):
error = get_validation_errors(response, "product")
self.assertEqual(error["code"], "bad-url")

def test_create_verzoekproduct_with_product_url_not_unique(self):
verzoek = VerzoekFactory.create()
verzoek_url = reverse(verzoek)

VerzoekProductFactory.create(verzoek=verzoek, product="https://example.com/")

list_url = reverse(VerzoekProduct)
data = {"verzoek": verzoek_url, "product": "https://example.com/"}

response = self.client.post(list_url, data)

self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

error = get_validation_errors(response, "nonFieldErrors")
self.assertEqual(error["code"], "unique")

def test_create_verzoekproduct_with_product_id(self):
verzoek = VerzoekFactory.create()
verzoek_url = reverse(verzoek)
Expand All @@ -133,6 +149,22 @@ def test_create_verzoekproduct_with_product_id(self):
verzoekproduct.product_code, data["productIdentificatie"]["code"]
)

def test_create_verzoekproduct_with_product_id_not_unique(self):
verzoek = VerzoekFactory.create()
verzoek_url = reverse(verzoek)

VerzoekProductFactory.create(verzoek=verzoek, product_code="test")

list_url = reverse(VerzoekProduct)
data = {"verzoek": verzoek_url, "productIdentificatie": {"code": "test"}}

response = self.client.post(list_url, data)

self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

error = get_validation_errors(response, "nonFieldErrors")
self.assertEqual(error["code"], "unique")

def test_create_verzoekproduct_without_product(self):
verzoek = VerzoekFactory.create()
verzoek_url = reverse(verzoek)
Expand Down
16 changes: 16 additions & 0 deletions src/verzoeken/api/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from django.utils.translation import ugettext_lazy as _

from rest_framework import exceptions, serializers
from rest_framework.validators import UniqueTogetherValidator
from vng_api_common.models import APICredential
from vng_api_common.validators import ResourceValidator
from zds_client import ClientError
Expand Down Expand Up @@ -106,3 +107,18 @@ def __call__(self, attrs: OrderedDict):
raise serializers.ValidationError(
self.message.format(object=object_type), code=self.code
)


class KlantProductUniqueTogetherValidator(UniqueTogetherValidator):
def enforce_required_fields(self, attrs):
# These attributes are optional, so this should not be enforced
return

def __call__(self, attrs):
# To ensure that the validation does not fail in case the attributes
# are missing (since they are not required)
if ("product" in self.fields and "product" not in attrs) or (
"product_code" in self.fields and "product_code" not in attrs
):
return
super().__call__(attrs)