def post(self, request: Request, pk: str): """ Select your preferred rates to buy a shipment label. """ shipment = request.user.shipment_set.get(pk=pk) if shipment.status == ShipmentStatus.purchased.value: raise PurplShipApiException( f"The shipment is '{shipment.status}' and therefore already {ShipmentStatus.purchased.value}", code='state_error', status_code=status.HTTP_409_CONFLICT) payload = { **Shipment(shipment).data, **SerializerDecorator[ShipmentPurchaseData](data=request.data).data } # Submit shipment to carriers response: Shipment = SerializerDecorator[ShipmentValidationData]( data=payload).save(user=request.user).instance # Update shipment state SerializerDecorator[ShipmentSerializer]( shipment, data=DP.to_dict(response)).save() return Response(Shipment(shipment).data)
class ShipmentRates(APIView): logging_methods = ['GET'] @swagger_auto_schema(tags=['Shipments'], operation_id=f"{ENDPOINT_ID}rates", operation_summary="Fetch new shipment rates", responses={ 200: Shipment(), 400: ErrorResponse() }) def get(self, request: Request, pk: str): """ Refresh the list of the shipment rates """ shipment = request.user.shipment_set.get(pk=pk) rate_response: RateResponse = SerializerDecorator[RateSerializer]( data=ShipmentData(shipment).data).save(user=shipment.user).instance payload: dict = DP.to_dict( dict(rates=Rate(rate_response.rates, many=True).data, messages=Message(rate_response.messages, many=True).data, selected_rate=None)) SerializerDecorator[ShipmentSerializer](shipment, data=payload).save() return Response(Shipment(shipment).data)
class ShipmentParcels(APIView): @swagger_auto_schema(tags=['Shipments'], operation_id=f"{ENDPOINT_ID}add_parcel", operation_summary="Add a shipment parcel", responses={ 200: Shipment(), 400: ErrorResponse() }, request_body=ParcelData()) def post(self, request: Request, pk: str): """ Add a parcel to an existing shipment for a multi-parcel shipment. """ shipment = request.user.shipment_set.get(pk=pk) if shipment.status == ShipmentStatus.purchased.value: raise PurplShipApiException("Shipment already 'purchased'", code='state_error', status_code=status.HTTP_409_CONFLICT) parcel = SerializerDecorator[ParcelSerializer](data=request.data).save( user=request.user).instance shipment.shipment_parcels.add(parcel) reset_related_shipment_rates(shipment) return Response(Shipment(shipment).data)
def get(self, request: Request, pk: str): """ Retrieve a shipment. """ shipment = request.user.shipment_set.get(pk=pk) return Response(Shipment(shipment).data)
class ShipmentCustoms(APIView): @swagger_auto_schema(tags=['Shipments'], operation_id=f"{ENDPOINT_ID}add_customs", operation_summary="Add a customs declaration", responses={ 200: Shipment(), 400: ErrorResponse() }, request_body=CustomsData()) def post(self, request: Request, pk: str): """ Add the customs declaration for the shipment if non existent. """ shipment = request.user.shipment_set.get(pk=pk) if shipment.status == ShipmentStatus.purchased.value: raise PurplShipApiException("Shipment already 'purchased'", code='state_error', status_code=status.HTTP_409_CONFLICT) if shipment.customs is not None: raise PurplShipApiException( "Shipment customs declaration already defined", code='state_error', status_code=status.HTTP_409_CONFLICT) SerializerDecorator[ShipmentSerializer]( shipment, data=dict(customs=request.data)).save() reset_related_shipment_rates(shipment) return Response(Shipment(shipment).data)
class ShippingList(APIView): @swagger_auto_schema( tags=['Proxy'], operation_id=f"{ENDPOINT_ID}buy_label", operation_summary="Buy a shipment label", request_body=ShippingRequest(), responses={200: Shipment(), 400: ErrorResponse()}, ) def post(self, request: Request): """ Once the shipping rates are retrieved, provide the required info to submit the shipment by specifying your preferred rate. """ payload = SerializerDecorator[ShippingRequestValidation](data=request.data).data response = Shipments.create( payload, resolve_tracking_url=( lambda shipment: reverse( "purpleserver.proxy:shipment-tracking", kwargs=dict(tracking_number=shipment.tracking_number, carrier_name=shipment.carrier_name) ) ) ) return Response(Shipment(response).data, status=status.HTTP_201_CREATED)
class ShipmentPurchase(APIView): @swagger_auto_schema(tags=['Shipments'], operation_id=f"{ENDPOINT_ID}purchase", operation_summary="Buy a shipment label", responses={ 200: Shipment(), 400: ErrorResponse() }, request_body=ShipmentPurchaseData()) def post(self, request: Request, pk: str): """ Select your preferred rates to buy a shipment label. """ shipment = request.user.shipment_set.get(pk=pk) if shipment.status == ShipmentStatus.purchased.value: raise PurplShipApiException( f"The shipment is '{shipment.status}' and therefore already {ShipmentStatus.purchased.value}", code='state_error', status_code=status.HTTP_409_CONFLICT) payload = { **Shipment(shipment).data, **SerializerDecorator[ShipmentPurchaseData](data=request.data).data } # Submit shipment to carriers response: Shipment = SerializerDecorator[ShipmentValidationData]( data=payload).save(user=request.user).instance # Update shipment state SerializerDecorator[ShipmentSerializer]( shipment, data=DP.to_dict(response)).save() return Response(Shipment(shipment).data)
def post(self, request: Request, pk: str): """ Add one or many options to your shipment.<br/> **eg:**<br/> - add shipment **insurance** - specify the preferred transaction **currency** - setup a **cash collected on delivery** option ```json { "insurance": 120, "currency": "USD" } ``` And many more, check additional options available in the [reference](#operation/all_references). """ shipment = request.user.shipment_set.get(pk=pk) if shipment.status == ShipmentStatus.purchased.value: raise PurplShipApiException("Shipment already 'purchased'", code='state_error', status_code=status.HTTP_409_CONFLICT) payload: dict = DP.to_dict(dict(options=request.data)) SerializerDecorator[ShipmentSerializer](shipment, data=payload).save() reset_related_shipment_rates(shipment) return Response(Shipment(shipment).data)
def get(self, request: Request): """ Retrieve all shipments. """ shipments = request.user.shipment_set.all() response = self.paginate_queryset(Shipment(shipments, many=True).data) return self.get_paginated_response(response)
def post(self, request: Request): """ Create a new shipment instance. """ shipment = SerializerDecorator[ShipmentSerializer]( data=request.data).save(user=request.user).instance return Response(Shipment(shipment).data, status=status.HTTP_201_CREATED)
def get(self, request: Request, pk: str): """ Refresh the list of the shipment rates """ shipment = request.user.shipment_set.get(pk=pk) rate_response: RateResponse = SerializerDecorator[RateSerializer]( data=ShipmentData(shipment).data).save(user=shipment.user).instance payload: dict = DP.to_dict( dict(rates=Rate(rate_response.rates, many=True).data, messages=Message(rate_response.messages, many=True).data, selected_rate=None)) SerializerDecorator[ShipmentSerializer](shipment, data=payload).save() return Response(Shipment(shipment).data)
def post(self, request: Request, pk: str): """ Add a parcel to an existing shipment for a multi-parcel shipment. """ shipment = request.user.shipment_set.get(pk=pk) if shipment.status == ShipmentStatus.purchased.value: raise PurplShipApiException("Shipment already 'purchased'", code='state_error', status_code=status.HTTP_409_CONFLICT) parcel = SerializerDecorator[ParcelSerializer](data=request.data).save( user=request.user).instance shipment.shipment_parcels.add(parcel) reset_related_shipment_rates(shipment) return Response(Shipment(shipment).data)
class ShipmentDetail(APIView): @swagger_auto_schema(tags=['Shipments'], operation_id=f"{ENDPOINT_ID}retrieve", operation_summary="Retrieve a shipment", responses={ 200: Shipment(), 400: ErrorResponse() }) def get(self, request: Request, pk: str): """ Retrieve a shipment. """ shipment = request.user.shipment_set.get(pk=pk) return Response(Shipment(shipment).data) @swagger_auto_schema(tags=['Shipments'], operation_id=f"{ENDPOINT_ID}cancel", operation_summary="Cancel a shipment", responses={ 200: OperationResponse(), 400: ErrorResponse() }) def delete(self, request: Request, pk: str): """ Void a shipment with the associated label. """ shipment = request.user.shipment_set.get(pk=pk) if shipment.status not in [ ShipmentStatus.purchased.value, ShipmentStatus.created.value ]: raise PurplShipApiException( f"The shipment is '{shipment.status}' and can therefore not be cancelled anymore...", code='state_error', status_code=status.HTTP_409_CONFLICT) if shipment.pickup_shipments.exists(): raise PurplShipApiException(( f"This shipment is scheduled for pickup '{shipment.pickup_shipments.first().pk}' " "Please cancel this shipment from the pickup before."), code='state_error', status_code=status.HTTP_409_CONFLICT) confirmation = SerializerDecorator[ShipmentCancelSerializer]( shipment, data={}).save() return Response(OperationResponse(confirmation.instance).data)
def post(self, request: Request): """ Once the shipping rates are retrieved, provide the required info to submit the shipment by specifying your preferred rate. """ payload = SerializerDecorator[ShippingRequestValidation](data=request.data).data response = Shipments.create( payload, resolve_tracking_url=( lambda shipment: reverse( "purpleserver.proxy:shipment-tracking", kwargs=dict(tracking_number=shipment.tracking_number, carrier_name=shipment.carrier_name) ) ) ) return Response(Shipment(response).data, status=status.HTTP_201_CREATED)
class ShipmentOptions(APIView): @swagger_auto_schema(tags=['Shipments'], operation_id=f"{ENDPOINT_ID}set_options", operation_summary="Add shipment options", responses={ 200: Shipment(), 400: ErrorResponse() }, request_body=openapi.Schema( title='options', type=openapi.TYPE_OBJECT, additional_properties=True, )) def post(self, request: Request, pk: str): """ Add one or many options to your shipment.<br/> **eg:**<br/> - add shipment **insurance** - specify the preferred transaction **currency** - setup a **cash collected on delivery** option ```json { "insurance": 120, "currency": "USD" } ``` And many more, check additional options available in the [reference](#operation/all_references). """ shipment = request.user.shipment_set.get(pk=pk) if shipment.status == ShipmentStatus.purchased.value: raise PurplShipApiException("Shipment already 'purchased'", code='state_error', status_code=status.HTTP_409_CONFLICT) payload: dict = DP.to_dict(dict(options=request.data)) SerializerDecorator[ShipmentSerializer](shipment, data=payload).save() reset_related_shipment_rates(shipment) return Response(Shipment(shipment).data)
def post(self, request: Request, pk: str): """ Add the customs declaration for the shipment if non existent. """ shipment = request.user.shipment_set.get(pk=pk) if shipment.status == ShipmentStatus.purchased.value: raise PurplShipApiException("Shipment already 'purchased'", code='state_error', status_code=status.HTTP_409_CONFLICT) if shipment.customs is not None: raise PurplShipApiException( "Shipment customs declaration already defined", code='state_error', status_code=status.HTTP_409_CONFLICT) SerializerDecorator[ShipmentSerializer]( shipment, data=dict(customs=request.data)).save() reset_related_shipment_rates(shipment) return Response(Shipment(shipment).data)
class ShipmentList(GenericAPIView): pagination_class = LimitOffsetPagination default_limit = 20 @swagger_auto_schema(tags=['Shipments'], operation_id=f"{ENDPOINT_ID}list", operation_summary="List all shipments", responses={ 200: Shipments(), 400: ErrorResponse() }) def get(self, request: Request): """ Retrieve all shipments. """ shipments = request.user.shipment_set.all() response = self.paginate_queryset(Shipment(shipments, many=True).data) return self.get_paginated_response(response) @swagger_auto_schema(tags=['Shipments'], operation_id=f"{ENDPOINT_ID}create", operation_summary="Create a shipment", responses={ 200: Shipment(), 400: ErrorResponse() }, request_body=ShipmentData()) def post(self, request: Request): """ Create a new shipment instance. """ shipment = SerializerDecorator[ShipmentSerializer]( data=request.data).save(user=request.user).instance return Response(Shipment(shipment).data, status=status.HTTP_201_CREATED)