Skip to content

Commit

Permalink
Add feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
Floris272 committed Aug 30, 2024
1 parent 38f3f4f commit 7a57ec2
Show file tree
Hide file tree
Showing 29 changed files with 524 additions and 153 deletions.
5 changes: 0 additions & 5 deletions .github/workflows/generate-postman-collection.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,6 @@ on:
jobs:
run:
runs-on: ubuntu-latest
# strategy:
# matrix:
# version: [ 'v1' ]

name: Run with version v1

steps:
- uses: actions/checkout@v4
Expand Down
6 changes: 0 additions & 6 deletions .github/workflows/generate-sdks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,6 @@ on:
jobs:
run:
runs-on: ubuntu-latest
# strategy:
# matrix:
# version: [ 'v1' ]

name: Run with version v1

steps:
- uses: actions/checkout@v4
- name: Use Node.js
Expand Down
6 changes: 0 additions & 6 deletions .github/workflows/lint-oas.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,6 @@ on:
jobs:
run:
runs-on: ubuntu-latest
# strategy:
# matrix:
# version: [ 'v1' ]

name: Run with version v1

steps:
- uses: actions/checkout@v4
- name: Use Node.js
Expand Down
22 changes: 1 addition & 21 deletions src/open_producten/conf/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,30 +75,10 @@

API_VERSION = "0.0.1"

SPECTACULAR_SETTINGS = {
SPECTACULAR_SETTINGS = { # TODO: may need to be expanded.
"SCHEMA_PATH_PREFIX": "/api/v1",
"TITLE": "Open Producten API",
"DESCRIPTION": _DESCRIPTION,
# "POSTPROCESSING_HOOKS": [
# "drf_spectacular.hooks.postprocess_schema_enums",
# "drf_spectacular.contrib.djangorestframework_camel_case.camelize_serializer_fields",
# ],
"TOS": None,
# Optional: MAY contain "name", "url", "email"
# "CONTACT": {
# "url": "https://github.com/maykinmedia/open-producten",
# "email": "[email protected]",
# },
# Optional: MUST contain "name", MAY contain URL
# "LICENSE": {
# "name": "UNLICENSED",
# },
"VERSION": API_VERSION,
# Tags defined in the global scope
"TAGS": [],
# Optional: MUST contain 'url', may contain "description"
# "EXTERNAL_DOCS": {
# "description": "Functional and technical documentation",
# "url": "https://open-producten.readthedocs.io/",
# },
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Generated by Django 4.2.13 on 2024-08-30 13:33

from decimal import Decimal
import django.core.validators
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
(
"producttypes",
"0003_alter_question_category_alter_question_product_type_and_more",
),
]

operations = [
migrations.AlterField(
model_name="priceoption",
name="amount",
field=models.DecimalField(
decimal_places=2,
help_text="The amount of the price option",
max_digits=8,
validators=[django.core.validators.MinValueValidator(Decimal("0.01"))],
verbose_name="Price",
),
),
]
4 changes: 2 additions & 2 deletions src/open_producten/producttypes/models/field.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@ class Meta:

def clean(self):
if self.type in self.choice_fields and not self.choices:
raise ValidationError(f"Choices are required for {self.type}")
raise ValidationError({"choices": f"Choices are required for {self.type}"})

if self.choices and self.type not in self.choice_fields:
raise ValidationError(f"{self.type} cannot have choices")
raise ValidationError({"choices": f"{self.type} cannot have choices"})

def __str__(self):
return self.name
1 change: 0 additions & 1 deletion src/open_producten/producttypes/models/price.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ class PriceOption(BaseModel):
verbose_name=_("Price"),
decimal_places=2,
max_digits=8,
default=0,
validators=[MinValueValidator(Decimal("0.01"))],
help_text=_("The amount of the price option"),
)
Expand Down
29 changes: 20 additions & 9 deletions src/open_producten/producttypes/serializers/category.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
from django.db import transaction

from rest_framework import serializers

from open_producten.producttypes.models import Category, ProductType
from open_producten.utils.serializers import check_for_duplicates_in_array

from .children import QuestionSerializer, UpnSerializer
from .children import QuestionSerializer, UniformProductNameSerializer


class SimpleProductTypeSerializer(serializers.ModelSerializer):
uniform_product_name = UpnSerializer()
uniform_product_name = UniformProductNameSerializer()

class Meta:
model = ProductType
exclude = ("id", "categories", "conditions", "tags", "related_product_types")
exclude = ("categories", "conditions", "tags", "related_product_types")


class CategorySerializer(serializers.ModelSerializer):
Expand All @@ -34,6 +37,16 @@ class Meta:
model = Category
exclude = ("path", "depth", "numchild")

def _handle_relations(self, instance, product_types):
errors = dict()
if product_types is not None:
check_for_duplicates_in_array(product_types, "product_type_ids", errors)
instance.product_types.set(product_types)

if errors:
raise serializers.ValidationError(errors)

@transaction.atomic()
def create(self, validated_data):
product_types = validated_data.pop("product_types")
parent_category = validated_data.pop("parent_category")
Expand All @@ -43,13 +56,14 @@ def create(self, validated_data):
else:
category = Category.add_root(**validated_data)

category.product_types.set(product_types)
self._handle_relations(category, product_types)
category.save()

return category

@transaction.atomic()
def update(self, instance, validated_data):
product_types = validated_data.pop("product_type_ids", None)
product_types = validated_data.pop("product_types", None)
parent_category = validated_data.pop(
"parent_category", "ignore"
) # None is a valid value
Expand All @@ -66,9 +80,6 @@ def update(self, instance, validated_data):
instance.refresh_from_db()

instance = super().update(instance, validated_data)

if product_types is not None:
instance.product_types.set(product_types)
self._handle_relations(instance, product_types)
instance.save()

return instance
38 changes: 28 additions & 10 deletions src/open_producten/producttypes/serializers/children.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from django.db import transaction

from rest_framework import serializers
from rest_framework.exceptions import ValidationError

from ..models import (
Condition,
Expand Down Expand Up @@ -48,27 +47,46 @@ def create(self, validated_data):
def update(self, instance, validated_data):
options = validated_data.pop("options", None)
price = super().update(instance, validated_data)
current_option_ids = list(price.options.values_list("id", flat=True))
option_errors = []

if options is not None:
for option in options:
current_option_ids = set(price.options.values_list("id", flat=True))
seen_option_ids = set()
for idx, option in enumerate(options):
option_id = option.pop("id", None)
if option_id is None:
PriceOption.objects.create(price=price, **option)

elif option_id in current_option_ids:

if option_id in seen_option_ids:
option_errors.append(
f"Duplicate option id {option_id} at index {idx}"
)
seen_option_ids.add(option_id)

existing_option = PriceOption.objects.get(id=option_id)
existing_option.amount = option["amount"]
existing_option.description = option["description"]
existing_option.save()
current_option_ids.remove(option_id)

else:
raise ValidationError(
f"Price option id {option_id} is not part of to price object."
)

PriceOption.objects.filter(id__in=current_option_ids).delete()
try:
PriceOption.objects.get(id=option_id)
option_errors.append(
f"Price option id {option_id} at index {idx} is not part of price object"
)
except PriceOption.DoesNotExist:
option_errors.append(
f"Price option id {option_id} at index {idx} does not exist"
)

if option_errors:
raise serializers.ValidationError({"options": option_errors})

PriceOption.objects.filter(
id__in=(current_option_ids - seen_option_ids)
).delete()

return price

Expand Down Expand Up @@ -102,7 +120,7 @@ class Meta:
fields = "__all__"


class UpnSerializer(serializers.ModelSerializer):
class UniformProductNameSerializer(serializers.ModelSerializer):
class Meta:
model = UniformProductName
fields = "__all__"
Expand Down
59 changes: 38 additions & 21 deletions src/open_producten/producttypes/serializers/producttype.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from rest_framework import serializers

from open_producten.utils.serializers import check_for_duplicates_in_array

from ..models import Category, Condition, ProductType, Tag, UniformProductName
from .children import (
ConditionSerializer,
Expand All @@ -10,6 +12,7 @@
PriceSerializer,
QuestionSerializer,
TagSerializer,
UniformProductNameSerializer,
)


Expand All @@ -33,10 +36,14 @@ class ProductTypeSerializer(serializers.ModelSerializer):
many=True, queryset=ProductType.objects.all(), default=[]
)

uniform_product_name = serializers.PrimaryKeyRelatedField(
queryset=UniformProductName.objects.all()
uniform_product_name_id = serializers.PrimaryKeyRelatedField(
queryset=UniformProductName.objects.all(),
write_only=True,
source="uniform_product_name",
)

uniform_product_name = UniformProductNameSerializer(read_only=True)

conditions = ConditionSerializer(many=True, read_only=True)
condition_ids = serializers.PrimaryKeyRelatedField(
many=True,
Expand Down Expand Up @@ -64,24 +71,40 @@ class Meta:
model = ProductType
fields = "__all__"

def _handle_relations(
self, instance, related_product_types, categories, tags, conditions
):
errors = dict()
if related_product_types is not None:
check_for_duplicates_in_array(
related_product_types, "related_product_types", errors
)
instance.related_product_types.set(related_product_types)
if categories is not None:
check_for_duplicates_in_array(categories, "category_ids", errors)
instance.categories.set(categories)
if tags is not None:
check_for_duplicates_in_array(tags, "tag_ids", errors)
instance.tags.set(tags)
if conditions is not None:
check_for_duplicates_in_array(conditions, "condition_ids", errors)
instance.conditions.set(conditions)

if errors:
raise serializers.ValidationError(errors)

@transaction.atomic()
def create(self, validated_data):
uniform_product_name_id = validated_data.pop("uniform_product_name")

related_product_types = validated_data.pop("related_product_types")
categories = validated_data.pop("categories")
conditions = validated_data.pop("conditions")
tags = validated_data.pop("tags")

product_type = ProductType.objects.create(
**validated_data, uniform_product_name=uniform_product_name_id
)

product_type.related_product_types.set(related_product_types)
product_type.categories.set(categories)
product_type.tags.set(tags)
product_type.conditions.set(conditions)
product_type = ProductType.objects.create(**validated_data)

self._handle_relations(
product_type, related_product_types, categories, tags, conditions
)
product_type.save()

return product_type
Expand All @@ -94,15 +117,9 @@ def update(self, instance, validated_data):
tags = validated_data.pop("tags", None)

instance = super().update(instance, validated_data)

if related_product_types is not None:
instance.related_product_types.set(related_product_types)
if categories is not None:
instance.categories.set(categories)
if tags is not None:
instance.tags.set(tags)
if conditions is not None:
instance.conditions.set(conditions)
self._handle_relations(
instance, related_product_types, categories, tags, conditions
)

instance.save()

Expand Down
Loading

0 comments on commit 7a57ec2

Please sign in to comment.