def post(self, request: Request, pk: str): """ Add the customs declaration for the shipment if non existent. """ shipment = (models.Shipment.access_by(request).exclude( status=ShipmentStatus.cancelled.value).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, ) payload: dict = dict(customs=DP.to_dict(request.data), shipment_rates=[], messages=[]) SerializerDecorator[ShipmentSerializer](shipment, data=payload, context=request).save() return Response(Shipment(shipment).data)
def delete(self, request: Request, pk: str): """ Void a shipment with the associated label. """ shipment = models.Shipment.access_by(request).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={}, context=request).save() return Response(OperationResponse(confirmation.instance).data)
def post(self, request: Request, pk: str): """ Select your preferred rates to buy a shipment label. """ shipment = (models.Shipment.access_by(request).exclude( status=ShipmentStatus.cancelled.value).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, ) # Submit shipment to carriers response: Shipment = (SerializerDecorator[ShipmentPurchaseSerializer]( context=request, data={ **Shipment(shipment).data, **SerializerDecorator[ShipmentPurchaseData](data=request.data).data, }, ).save().instance) # Update shipment state SerializerDecorator[ShipmentSerializer](shipment, data=DP.to_dict(response), context=request).save() create_shipment_tracker(shipment, context=request) 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 = (models.Shipment.access_by(request).exclude( status=ShipmentStatus.cancelled.value).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 = dict(options=DP.to_dict(request.data), shipment_rates=[], messages=[]) SerializerDecorator[ShipmentSerializer](shipment, data=payload).save() return Response(Shipment(shipment).data)
def patch(self, request: Request, pk: str): """ modify an existing parcel's details. """ parcel = models.Parcel.access_by(request).get(pk=pk) shipment = parcel.shipment_parcels.first() if shipment is not None and shipment.status == ShipmentStatus.purchased.value: raise PurplShipApiException( "The shipment related to this parcel has been 'purchased' and can no longer be modified", status_code=status.HTTP_409_CONFLICT, code='state_error') SerializerDecorator[ParcelSerializer](parcel, data=request.data).save() reset_related_shipment_rates(shipment) return Response(Parcel(parcel).data)
def delete(self, request: Request, pk: str): """ Discard an address. """ address = models.Address.access_by(request).get(pk=pk) shipment = address.shipper.first() or address.recipient.first() if shipment is not None: raise PurplShipApiException( "This address is linked to a shipment and cannot be removed", status_code=status.HTTP_409_CONFLICT, code='state_error') address.delete(keep_parents=True) serializer = Operation(dict(operation="Discard address", success=True)) return Response(serializer.data)
def patch(self, request: Request, pk: str): """ update an address. """ address = models.Address.access_by(request).get(pk=pk) shipment = address.shipper.first() or address.recipient.first() if shipment is not None and shipment.status == ShipmentStatus.purchased.value: raise PurplShipApiException( "The shipment related to this address has been 'purchased' and can no longer be modified", status_code=status.HTTP_409_CONFLICT, code='state_error') SerializerDecorator[AddressSerializer](address, data=request.data).save() reset_related_shipment_rates(shipment) return Response(Address(address).data)
def delete(self, request: Request, pk: str, ck: str): """ Discard a customs commodity. """ customs = models.Customs.access_by(request).get(pk=pk) shipment = customs.shipment_set.first() if shipment is not None and shipment.status == ShipmentStatus.purchased.value: raise PurplShipApiException( "The shipment related to this customs info has been 'purchased' and cannot be modified", status_code=status.HTTP_409_CONFLICT, code='state_error') commodity = customs.commodities.get(pk=ck) commodity.delete(keep_parents=True) serializer = Operation( dict(operation="Discard customs commodity", success=True)) return Response(serializer.data)
def post(self, request: Request, pk: str): """ Add a customs commodity. """ customs = models.Customs.access_by(request).get(pk=pk) shipment = customs.shipment_set.first() if shipment.status == ShipmentStatus.purchased.value: raise PurplShipApiException( "The associated shipment is already 'purchased'", status_code=status.HTTP_409_CONFLICT, code='state_error') commodity = SerializerDecorator[CommoditySerializer]( data=request.data, context=request).save().instance customs.commodities.add(commodity) return Response(Customs(commodity.customs_set.first()).data)
def patch(self, request: Request, pk: str): """ modify an existing customs declaration. """ customs = models.Customs.access_by(request).get(pk=pk) shipment = customs.shipment_set.first() if shipment is not None and shipment.status == ShipmentStatus.purchased.value: raise PurplShipApiException( "The shipment related to this customs info has been 'purchased' and can no longer be modified", status_code=status.HTTP_409_CONFLICT, code='state_error') SerializerDecorator[CustomsSerializer](customs, data=request.data, context=request).save() reset_related_shipment_rates(shipment) return Response(Customs(customs).data)
def post(self, request: Request, pk: str): """ Add a parcel to an existing shipment for a multi-parcel shipment. """ shipment = (models.Shipment.access_by(request).exclude( status=ShipmentStatus.cancelled.value).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, context=request).save().instance) shipment.shipment_parcels.add(parcel) reset_related_shipment_rates(shipment) return Response(Shipment(shipment).data)
def delete(self, request: Request, pk: str): """ Remove a parcel. """ parcel = models.Parcel.access_by(request).get(pk=pk) shipment = parcel.shipment_parcels.first() if shipment is not None and ( shipment.status == ShipmentStatus.purchased.value or len(shipment.shipment_parcels.all()) == 1): raise PurplShipApiException( "A shipment attached to this parcel is purchased or has only one parcel. The parcel cannot be removed!", status_code=status.HTTP_409_CONFLICT, code='state_error') parcel.delete(keep_parents=True) shipment.shipment_parcels.set( shipment.shipment_parcels.exclude(id=parcel.id)) serializer = Operation(dict(operation="Remove parcel", success=True)) reset_related_shipment_rates(shipment) return Response(serializer.data)