Refactored order creation logic to use new serializers and transaction handling, improving validation and modularity. Introduced admin and public endpoints for shop configuration with sensitive fields protected. Enhanced Zásilkovna (Packeta) integration, including packet widget template, new API fields, and improved error handling. Added django-silk for profiling, updated requirements and settings, and improved frontend Orval config for API client generation.
142 lines
4.8 KiB
Python
142 lines
4.8 KiB
Python
from rest_framework import viewsets, mixins, status
|
|
from rest_framework.decorators import action
|
|
from rest_framework.response import Response
|
|
from django.template import loader
|
|
|
|
from drf_spectacular.utils import extend_schema, extend_schema_view, OpenApiResponse, OpenApiParameter, OpenApiTypes
|
|
|
|
from backend.configuration.models import ShopConfiguration
|
|
|
|
from .models import ZasilkovnaShipment, ZasilkovnaPacket
|
|
from .serializers import (
|
|
ZasilkovnaShipmentSerializer,
|
|
ZasilkovnaPacketSerializer,
|
|
TrackingURLSerializer,
|
|
)
|
|
|
|
# -- SHIPMENT --
|
|
|
|
@extend_schema_view(
|
|
list=extend_schema(
|
|
tags=["Packeta-Shipment"],
|
|
summary="Hromadný shipment",
|
|
description="Returns a paginated list of Packeta (Zásilkovna) shipments.",
|
|
responses=ZasilkovnaShipmentSerializer,
|
|
),
|
|
retrieve=extend_schema(
|
|
tags=["Packeta-Shipment"],
|
|
summary="Detail hromadné zásilky",
|
|
description="Returns detail for a single shipment.",
|
|
responses=ZasilkovnaShipmentSerializer,
|
|
),
|
|
)
|
|
class ZasilkovnaShipmentViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet,):
|
|
queryset = ZasilkovnaShipment.objects.all().order_by("-created_at")
|
|
serializer_class = ZasilkovnaShipmentSerializer
|
|
|
|
|
|
|
|
|
|
|
|
# -- PACKET --
|
|
|
|
@extend_schema_view(
|
|
retrieve=extend_schema(
|
|
tags=["Packet"],
|
|
summary="Packet",
|
|
description="#TODO: Popis endpointu",
|
|
responses={200: ZasilkovnaPacketSerializer},
|
|
)
|
|
)
|
|
class ZasilkovnaPacketViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
|
|
queryset = ZasilkovnaPacket.objects.all()
|
|
serializer_class = ZasilkovnaPacketSerializer
|
|
|
|
@extend_schema(
|
|
tags=["Packet"],
|
|
summary="Get public tracking URL",
|
|
description="Returns the public Zásilkovna tracking URL derived from the packet's barcode.",
|
|
responses=OpenApiResponse(response=TrackingURLSerializer),
|
|
parameters=[
|
|
OpenApiParameter(name="pk", location=OpenApiParameter.PATH, description="Packet ID", required=True, type=int),
|
|
],
|
|
request=None,
|
|
)
|
|
@action(detail=True, methods=["get"], url_path="tracking-url")
|
|
def tracking_url(self, request, pk=None):
|
|
packet: ZasilkovnaPacket = self.get_object()
|
|
data = {
|
|
"barcode": packet.barcode,
|
|
"tracking_url": packet.get_tracking_url(),
|
|
}
|
|
return Response(data)
|
|
|
|
|
|
#HOTOVO
|
|
@extend_schema(
|
|
tags=["Packet"],
|
|
summary="Order shipping",
|
|
description=(
|
|
"Objedná přepravu přes API Packety,"
|
|
"podle existujicího objektu, kde je od uživatele uložený id od místa poslání."
|
|
),
|
|
request=None,
|
|
responses=OpenApiResponse(response=ZasilkovnaPacketSerializer),
|
|
parameters=[
|
|
OpenApiParameter(name="pk", location=OpenApiParameter.PATH, description="Packet ID", required=True, type=int),
|
|
],
|
|
)
|
|
@action(detail=True, methods=["patch"], url_path="order-shipping")
|
|
def order_shipping(self, request, pk=None):
|
|
packet: ZasilkovnaPacket = self.get_object()
|
|
packet.order_shipping()
|
|
serializer = self.get_serializer(packet)
|
|
return Response(serializer.data, status=status.HTTP_200_OK)
|
|
|
|
|
|
#HOTOVO
|
|
@extend_schema(
|
|
tags=["Packet"],
|
|
summary="Cancel packet",
|
|
description=(
|
|
"Cancels the packet through the Packeta API and updates its state to CANCELED. "
|
|
"No request body is required."
|
|
),
|
|
request=None,
|
|
responses=OpenApiResponse(response=ZasilkovnaPacketSerializer),
|
|
parameters=[
|
|
OpenApiParameter(name="pk", location=OpenApiParameter.PATH, description="Packet ID", required=True, type=int),
|
|
],
|
|
)
|
|
@action(detail=True, methods=["patch"], url_path="cancel")
|
|
def cancel(self, request, pk=None):
|
|
packet: ZasilkovnaPacket = self.get_object()
|
|
packet.cancel_packet()
|
|
serializer = self.get_serializer(packet)
|
|
return Response(serializer.data, status=status.HTTP_200_OK)
|
|
|
|
|
|
#TODO: dodělat/domluvit se
|
|
@extend_schema(
|
|
tags=["Packet"],
|
|
summary="Get widget for user, to select pickup point.",
|
|
description=(
|
|
"Returns HTML widget for user to select pickup point. "
|
|
"No request body is required."
|
|
),
|
|
request=None,
|
|
responses={200: OpenApiResponse(response=TrackingURLSerializer)},
|
|
)
|
|
@action(detail=True, methods=["get"], url_path="pickup-point-widget")
|
|
def pickup_point_widget(self, request):
|
|
|
|
#https://configurator.widget.packeta.com/cs
|
|
|
|
widget_html = loader.render_to_string(
|
|
"zasilkovna/pickup_point_widget.html",
|
|
{
|
|
"api_key": ShopConfiguration.get_solo().zasilkovna_widget_api_key,
|
|
}
|
|
)
|
|
|
|
return Response({"widget_html": widget_html}) |