Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/46 producttype nl api #23

Merged
merged 19 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from 4 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
4 changes: 4 additions & 0 deletions src/open_producten/conf/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@
"SWAGGER_UI_DIST": "SIDECAR",
"SWAGGER_UI_FAVICON_HREF": "SIDECAR",
"REDOC_DIST": "SIDECAR",
"POSTPROCESSING_HOOKS": (
"drf_spectacular.hooks.postprocess_schema_enums",
"open_producten.utils.spectacular_hooks.custom_postprocessing_hook",
),
}

#
Expand Down
26 changes: 26 additions & 0 deletions src/open_producten/producttypen/router.py
Floris272 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from django.urls import include, path

from rest_framework.routers import DefaultRouter

from open_producten.producttypen.views import (
LinkViewSet,
OnderwerpViewSet,
PrijsViewSet,
ProductTypeViewSet,
VraagViewSet,
)

ProductTypenRouter = DefaultRouter()
ProductTypenRouter.register("producttypen", ProductTypeViewSet, basename="producttype")

ProductTypenRouter.register(r"links", LinkViewSet, basename="link")

ProductTypenRouter.register(r"prijzen", PrijsViewSet, basename="prijs")

ProductTypenRouter.register(r"vragen", VraagViewSet, basename="vraag")

ProductTypenRouter.register("onderwerpen", OnderwerpViewSet, basename="onderwerp")

product_type_urlpatterns = [
path("", include(ProductTypenRouter.urls)),
]
17 changes: 17 additions & 0 deletions src/open_producten/producttypen/serializers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from .bestand import BestandSerializer
from .link import LinkSerializer
from .onderwerp import OnderwerpSerializer
from .prijs import PrijsOptieSerializer, PrijsSerializer
from .producttype import ProductTypeActuelePrijsSerializer, ProductTypeSerializer
from .vraag import VraagSerializer

__all__ = [
"LinkSerializer",
"BestandSerializer",
"OnderwerpSerializer",
"PrijsSerializer",
"PrijsOptieSerializer",
"ProductTypeSerializer",
"ProductTypeActuelePrijsSerializer",
"VraagSerializer",
]
14 changes: 14 additions & 0 deletions src/open_producten/producttypen/serializers/bestand.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from rest_framework import serializers

from open_producten.producttypen.models import Bestand, ProductType


# TODO does not have viewset
Coperh marked this conversation as resolved.
Show resolved Hide resolved
class BestandSerializer(serializers.ModelSerializer):
product_type_id = serializers.PrimaryKeyRelatedField(
source="product_type", queryset=ProductType.objects.all()
)

class Meta:
model = Bestand
exclude = ("product_type",)
Floris272 marked this conversation as resolved.
Show resolved Hide resolved
13 changes: 13 additions & 0 deletions src/open_producten/producttypen/serializers/link.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from rest_framework import serializers

from open_producten.producttypen.models import Link, ProductType


class LinkSerializer(serializers.ModelSerializer):
product_type_id = serializers.PrimaryKeyRelatedField(
source="product_type", queryset=ProductType.objects.all()
)

class Meta:
model = Link
exclude = ("product_type",)
Floris272 marked this conversation as resolved.
Show resolved Hide resolved
106 changes: 106 additions & 0 deletions src/open_producten/producttypen/serializers/onderwerp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
from django.core.exceptions import ValidationError
from django.db import transaction

from rest_framework import serializers

from open_producten.producttypen.models import (
Onderwerp,
ProductType,
UniformeProductNaam,
)
from open_producten.utils.serializers import build_array_duplicates_error_message

from .vraag import VraagSerializer


class SimpleProductTypeSerializer(serializers.ModelSerializer):
Coperh marked this conversation as resolved.
Show resolved Hide resolved
uniforme_product_naam = serializers.SlugRelatedField(
slug_field="uri", queryset=UniformeProductNaam.objects.all()
)

class Meta:
model = ProductType
exclude = (
"onderwerpen",
# "organisaties",
# "locaties",
# "contacten",
)
Floris272 marked this conversation as resolved.
Show resolved Hide resolved


class OnderwerpSerializer(serializers.ModelSerializer):
hoofd_onderwerp = serializers.PrimaryKeyRelatedField(
queryset=Onderwerp.objects.all(),
allow_null=True,
)
product_typen = SimpleProductTypeSerializer(many=True, read_only=True)
vragen = VraagSerializer(many=True, read_only=True)

product_type_ids = serializers.PrimaryKeyRelatedField(
many=True,
queryset=ProductType.objects.all(),
default=[],
write_only=True,
source="product_typen",
)

class Meta:
model = Onderwerp
exclude = ("path", "depth", "numchild")

def _handle_relations(self, instance, product_typen: list[ProductType]):
errors = dict()
if product_typen is not None:
build_array_duplicates_error_message(
product_typen, "product_type_ids", errors
)
instance.product_typen.set(product_typen)

if errors:
raise serializers.ValidationError(errors)
Floris272 marked this conversation as resolved.
Show resolved Hide resolved
Floris272 marked this conversation as resolved.
Show resolved Hide resolved

def _validate_onderwerp(self, onderwerp):
try:
onderwerp.clean()
Floris272 marked this conversation as resolved.
Show resolved Hide resolved
except ValidationError as err:
raise serializers.ValidationError({"hoofd_onderwerp": err.message})

@transaction.atomic()
def create(self, validated_data):
product_typen = validated_data.pop("product_typen")
hoofd_onderwerp = validated_data.pop("hoofd_onderwerp")

if hoofd_onderwerp:
onderwerp = hoofd_onderwerp.add_child(**validated_data)
else:
onderwerp = Onderwerp.add_root(**validated_data)

self._validate_onderwerp(onderwerp)
self._handle_relations(onderwerp, product_typen)
onderwerp.save()

return onderwerp

@transaction.atomic()
def update(self, instance, validated_data):
Coperh marked this conversation as resolved.
Show resolved Hide resolved
product_typen = validated_data.pop("product_typen", None)
hoofd_onderwerp = validated_data.pop(
"hoofd_onderwerp", "ignore"
) # None is a valid value

if hoofd_onderwerp != "ignore":
instance_hoofd_onderwerp = instance.get_parent()
if hoofd_onderwerp is None and instance_hoofd_onderwerp is not None:
last_root = Onderwerp.get_last_root_node()
instance.move(last_root, "sorted-sibling")

elif hoofd_onderwerp != instance_hoofd_onderwerp:
instance.move(hoofd_onderwerp, "sorted-child")
Floris272 marked this conversation as resolved.
Show resolved Hide resolved

instance.refresh_from_db()
Floris272 marked this conversation as resolved.
Show resolved Hide resolved

instance = super().update(instance, validated_data)
self._validate_onderwerp(instance)
self._handle_relations(instance, product_typen)
instance.save()
return instance
99 changes: 99 additions & 0 deletions src/open_producten/producttypen/serializers/prijs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
from django.db import transaction
from django.utils.translation import gettext_lazy as _

from rest_framework import serializers

from ..models import Prijs, PrijsOptie, ProductType


class PrijsOptieSerializer(serializers.ModelSerializer):
id = serializers.UUIDField(required=False)

class Meta:
model = PrijsOptie
exclude = ("prijs",)


class PrijsSerializer(serializers.ModelSerializer):
prijsopties = PrijsOptieSerializer(many=True, default=[])
product_type_id = serializers.PrimaryKeyRelatedField(
source="product_type", queryset=ProductType.objects.all()
)

class Meta:
model = Prijs
exclude = ("product_type",)

def validate_prijsopties(self, opties: list[PrijsOptie]) -> list[PrijsOptie]:
if len(opties) == 0:
raise serializers.ValidationError(_("Er is minimaal één optie vereist."))
return opties

@transaction.atomic()
def create(self, validated_data):
prijsopties = validated_data.pop("prijsopties")
product_type = validated_data.pop("product_type")

prijs = Prijs.objects.create(**validated_data, product_type=product_type)

for optie in prijsopties:
PrijsOptie.objects.create(prijs=prijs, **optie)

return prijs

@transaction.atomic()
def update(self, instance, validated_data):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one is just confusing TBH.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think first you should check for duplicate IDS, then do the update/create stuff

if opties is not None:
    
    optie_errors = has duplicate

    if optie_errors:
        raise ValidationError
    else:
        # do the update logic

    

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also their is the object not existing thing .

IDK, I really dont like this endpoint

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved validation to PrijsOptieValidator

opties = validated_data.pop("prijsopties", None)
prijs = super().update(instance, validated_data)
optie_errors = []

if opties is not None:
current_optie_ids = set(
prijs.prijsopties.values_list("id", flat=True).distinct()
)
seen_optie_ids = set()
for idx, optie in enumerate(opties):
optie_id = optie.pop("id", None)
if optie_id is None:
PrijsOptie.objects.create(prijs=prijs, **optie)

elif optie_id in current_optie_ids:

if optie_id in seen_optie_ids:
optie_errors.append(
_("Dubbele optie id {} op index {}.".format(optie_id, idx))
)
seen_optie_ids.add(optie_id)

existing_optie = PrijsOptie.objects.get(id=optie_id)
existing_optie.bedrag = optie["bedrag"]
existing_optie.beschrijving = optie["beschrijving"]
existing_optie.save()

else:
try:
PrijsOptie.objects.get(id=optie_id)
optie_errors.append(
_(
"Prijs optie id {} op index {} is niet onderdeel van het prijs object.".format(
optie_id, idx
)
)
)
except PrijsOptie.DoesNotExist:
optie_errors.append(
_(
"Prijs optie id {} op index {} bestaat niet.".format(
optie_id, idx
)
)
)

if optie_errors:
raise serializers.ValidationError({"prijsopties": optie_errors})

PrijsOptie.objects.filter(
id__in=(current_optie_ids - seen_optie_ids)
).delete()

return prijs
Loading
Loading