Ejemplo n.º 1
0
    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)
Ejemplo n.º 2
0
    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)
Ejemplo n.º 3
0
    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)
Ejemplo n.º 4
0
    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)
Ejemplo n.º 5
0
    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)
Ejemplo n.º 6
0
    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)
Ejemplo n.º 7
0
    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)
Ejemplo n.º 8
0
    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)
Ejemplo n.º 9
0
    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)
Ejemplo n.º 10
0
    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)
Ejemplo n.º 11
0
    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)
Ejemplo n.º 12
0
    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)