karrio-server-proxy 2025.5rc1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,57 @@
1
+ import logging
2
+ from django.urls import path
3
+ from rest_framework import status
4
+ from rest_framework.request import Request
5
+ from rest_framework.response import Response
6
+
7
+ from karrio.server.core.views.api import APIView
8
+ from karrio.server.core.serializers import (
9
+ RateRequest,
10
+ RateResponse,
11
+ ErrorResponse,
12
+ ErrorMessages,
13
+ )
14
+ from karrio.server.core.gateway import Rates
15
+ from karrio.server.proxy.router import router
16
+ import karrio.server.openapi as openapi
17
+
18
+ logger = logging.getLogger(__name__)
19
+ ENDPOINT_ID = "@@" # This endpoint id is used to make operation ids unique make sure not to duplicate
20
+
21
+ DESCRIPTIONS = """
22
+ The Shipping process begins by fetching rates for your shipment.
23
+ Use this service to fetch a shipping rates available.
24
+ """
25
+
26
+
27
+ class RateViewAPI(APIView):
28
+ throttle_scope = "carrier_request"
29
+
30
+ @openapi.extend_schema(
31
+ tags=["Proxy"],
32
+ operation_id=f"{ENDPOINT_ID}fetch_rates",
33
+ extensions={"x-operationId": "fetchRates"},
34
+ summary="Fetch shipment rates",
35
+ description=DESCRIPTIONS,
36
+ responses={
37
+ 200: RateResponse(),
38
+ 400: ErrorResponse(),
39
+ 424: ErrorMessages(),
40
+ 500: ErrorResponse(),
41
+ },
42
+ request=RateRequest(),
43
+ )
44
+ def post(self, request: Request):
45
+ payload = RateRequest.map(data=request.data).data
46
+
47
+ response = Rates.fetch(payload, context=request)
48
+ status_code = (
49
+ status.HTTP_207_MULTI_STATUS
50
+ if len(response.messages) > 0
51
+ else status.HTTP_200_OK
52
+ )
53
+
54
+ return Response(RateResponse(response).data, status=status_code)
55
+
56
+
57
+ router.urls.append(path("proxy/rates", RateViewAPI.as_view(), name="shipment-rates"))
@@ -0,0 +1,139 @@
1
+ import logging
2
+ from django.urls import path
3
+ from rest_framework import status
4
+ from rest_framework.request import Request
5
+ from rest_framework.reverse import reverse
6
+ from rest_framework.response import Response
7
+
8
+ import karrio.server.openapi as openapi
9
+ import karrio.server.serializers as serializers
10
+ import karrio.server.core.dataunits as dataunits
11
+ import karrio.server.providers.models as providers
12
+ from karrio.server.core.views.api import APIView
13
+ from karrio.server.proxy.router import router
14
+ from karrio.server.core.gateway import Shipments
15
+ from karrio.server.core.serializers import (
16
+ COUNTRIES,
17
+ ShippingRequest,
18
+ ShipmentCancelRequest,
19
+ ShipmentContent,
20
+ ShipmentDetails,
21
+ OperationResponse,
22
+ Address as BaseAddress,
23
+ ErrorResponse,
24
+ ErrorMessages,
25
+ )
26
+
27
+ ENDPOINT_ID = "@@@" # This endpoint id is used to make operation ids unique make sure not to duplicate
28
+ logger = logging.getLogger(__name__)
29
+
30
+
31
+ class Address(BaseAddress):
32
+ city = serializers.CharField(required=True, help_text="The address city")
33
+ person_name = serializers.CharField(required=True, help_text="attention to")
34
+ country_code = serializers.ChoiceField(
35
+ required=True, choices=COUNTRIES, help_text="The address country code"
36
+ )
37
+ address_line1 = serializers.CharField(
38
+ required=True, help_text="The address line with street number"
39
+ )
40
+
41
+
42
+ class ShippingRequestValidation(ShippingRequest):
43
+ shipper = Address(
44
+ required=True, help_text="The origin address of the shipment (address from)"
45
+ )
46
+ recipient = Address(
47
+ required=True, help_text="The shipment destination address (address to)"
48
+ )
49
+
50
+
51
+ class ShippingResponse(serializers.EntitySerializer, ShipmentContent, ShipmentDetails):
52
+ object_type = serializers.CharField(
53
+ default="shipment", help_text="Specifies the object type"
54
+ )
55
+
56
+
57
+ class ShippingDetails(APIView):
58
+ throttle_scope = "carrier_request"
59
+
60
+ @openapi.extend_schema(
61
+ tags=["Proxy"],
62
+ operation_id=f"{ENDPOINT_ID}buy_label",
63
+ extensions={"x-operationId": "buyLabel"},
64
+ summary="Buy a shipment label",
65
+ request=ShippingRequest(),
66
+ responses={
67
+ 200: ShippingResponse(),
68
+ 400: ErrorResponse(),
69
+ 424: ErrorMessages(),
70
+ 500: ErrorResponse(),
71
+ },
72
+ )
73
+ def post(self, request: Request):
74
+ """
75
+ Once the shipping rates are retrieved, provide the required info to
76
+ submit the shipment by specifying your preferred rate.
77
+ """
78
+ payload = ShippingRequestValidation.map(data=request.data).data
79
+
80
+ response = Shipments.create(
81
+ payload,
82
+ resolve_tracking_url=(
83
+ lambda tracking_number, carrier_name: reverse(
84
+ "karrio.server.proxy:shipment-tracking",
85
+ kwargs=dict(
86
+ tracking_number=tracking_number, carrier_name=carrier_name
87
+ ),
88
+ )
89
+ ),
90
+ )
91
+
92
+ return Response(ShippingResponse(response).data, status=status.HTTP_200_OK)
93
+
94
+
95
+ class ShippingCancel(APIView):
96
+ throttle_scope = "carrier_request"
97
+
98
+ @openapi.extend_schema(
99
+ tags=["Proxy"],
100
+ operation_id=f"{ENDPOINT_ID}void_label",
101
+ extensions={"x-operationId": "voidLabel"},
102
+ summary="Void a shipment label",
103
+ request=ShipmentCancelRequest(),
104
+ responses={
105
+ 202: OperationResponse(),
106
+ 400: ErrorResponse(),
107
+ 424: ErrorMessages(),
108
+ },
109
+ parameters=[
110
+ openapi.OpenApiParameter(
111
+ "carrier_name",
112
+ location=openapi.OpenApiParameter.PATH,
113
+ type=openapi.OpenApiTypes.STR,
114
+ enum=dataunits.CARRIER_NAMES,
115
+ ),
116
+ ],
117
+ )
118
+ def post(self, request: Request, carrier_name: str):
119
+ """
120
+ Cancel a shipment and the label previously created
121
+ """
122
+ payload = ShipmentCancelRequest.map(data=request.data).data
123
+ response = Shipments.cancel(payload, context=request, carrier_name=carrier_name)
124
+
125
+ return Response(
126
+ OperationResponse(response).data, status=status.HTTP_202_ACCEPTED
127
+ )
128
+
129
+
130
+ router.urls.append(
131
+ path("proxy/shipping", ShippingDetails.as_view(), name="shipping-request")
132
+ )
133
+ router.urls.append(
134
+ path(
135
+ "proxy/shipping/<carrier_name>/cancel",
136
+ ShippingCancel.as_view(),
137
+ name="shipping-cancel",
138
+ )
139
+ )
@@ -0,0 +1,165 @@
1
+ import logging
2
+ from django.urls import path
3
+ from rest_framework import status
4
+ from rest_framework.response import Response
5
+ from rest_framework.request import Request
6
+
7
+ import karrio.server.openapi as openapi
8
+ import karrio.server.core.dataunits as dataunits
9
+ from karrio.server.core.views.api import APIView
10
+ from karrio.server.core.serializers import (
11
+ TrackingData,
12
+ TrackingResponse,
13
+ ErrorResponse,
14
+ ErrorMessages,
15
+ )
16
+ from karrio.server.core.gateway import Shipments
17
+ from karrio.server.proxy.router import router
18
+
19
+ logger = logging.getLogger(__name__)
20
+ ENDPOINT_ID = "@@@@" # This endpoint id is used to make operation ids unique make sure not to duplicate
21
+
22
+
23
+ class TrackingAPIView(APIView):
24
+ throttle_scope = "carrier_request"
25
+
26
+ @openapi.extend_schema(
27
+ tags=["Proxy"],
28
+ operation_id=f"{ENDPOINT_ID}get_tracking",
29
+ extensions={"x-operationId": "getTracking"},
30
+ summary="Get tracking details",
31
+ request=TrackingData(),
32
+ responses={
33
+ 200: TrackingResponse(),
34
+ 400: ErrorResponse(),
35
+ 424: ErrorMessages(),
36
+ 500: ErrorResponse(),
37
+ },
38
+ parameters=[
39
+ openapi.OpenApiParameter(
40
+ "hub",
41
+ location=openapi.OpenApiParameter.QUERY,
42
+ type=openapi.OpenApiTypes.STR,
43
+ required=False,
44
+ ),
45
+ ],
46
+ )
47
+ def post(self, request: Request):
48
+ """
49
+ You can track a shipment by specifying the carrier and the shipment tracking number.
50
+ """
51
+ query = request.query_params
52
+ serializer = TrackingData(data=request.data)
53
+ serializer.is_valid(raise_exception=True)
54
+ data = serializer.validated_data
55
+ carrier_filter = {
56
+ **{k: v for k, v in query.items() if k != "hub"},
57
+ # If a hub is specified, use the hub as carrier to track the package
58
+ "carrier_name": (
59
+ query.get("hub") if "hub" in query else data["carrier_name"]
60
+ ),
61
+ }
62
+ data = {
63
+ **data,
64
+ "tracking_numbers": [data["tracking_number"]],
65
+ "options": (
66
+ {data["tracking_number"]: {"carrier": data["carrier_name"]}}
67
+ if "hub" in query
68
+ else {}
69
+ ),
70
+ }
71
+
72
+ response = Shipments.track(data, context=request, **carrier_filter)
73
+
74
+ return Response(
75
+ TrackingResponse(response).data,
76
+ status=(
77
+ status.HTTP_200_OK
78
+ if response.tracking is not None
79
+ else status.HTTP_404_NOT_FOUND
80
+ ),
81
+ )
82
+
83
+
84
+ class TrackingAPI(APIView):
85
+ throttle_scope = "carrier_request"
86
+ logging_methods = ["GET"]
87
+
88
+ @openapi.extend_schema(
89
+ tags=["Proxy"],
90
+ operation_id=f"{ENDPOINT_ID}track_shipment",
91
+ extensions={"x-operationId": "trackShipment"},
92
+ summary="Track a shipment",
93
+ deprecated=True,
94
+ responses={
95
+ 200: TrackingResponse(),
96
+ 400: ErrorResponse(),
97
+ 424: ErrorMessages(),
98
+ 500: ErrorResponse(),
99
+ },
100
+ parameters=[
101
+ openapi.OpenApiParameter(
102
+ "carrier_name",
103
+ location=openapi.OpenApiParameter.PATH,
104
+ type=openapi.OpenApiTypes.STR,
105
+ enum=dataunits.NON_HUBS_CARRIERS,
106
+ required=True,
107
+ ),
108
+ openapi.OpenApiParameter(
109
+ "tracking_number",
110
+ location=openapi.OpenApiParameter.PATH,
111
+ type=openapi.OpenApiTypes.STR,
112
+ required=True,
113
+ ),
114
+ openapi.OpenApiParameter(
115
+ "hub",
116
+ location=openapi.OpenApiParameter.QUERY,
117
+ type=openapi.OpenApiTypes.STR,
118
+ required=False,
119
+ ),
120
+ ],
121
+ )
122
+ def get(self, request: Request, carrier_name: str, tracking_number: str):
123
+ """
124
+ You can track a shipment by specifying the carrier and the shipment tracking number.
125
+ """
126
+ query = request.query_params
127
+ carrier_filter = {
128
+ **{k: v for k, v in query.items() if k != "hub"},
129
+ # If a hub is specified, use the hub as carrier to track the package
130
+ "carrier_name": (query.get("hub") if "hub" in query else carrier_name),
131
+ }
132
+ data = {
133
+ "tracking_numbers": [tracking_number],
134
+ "options": (
135
+ {tracking_number: {"carrier": carrier_name}} if "hub" in query else {}
136
+ ),
137
+ }
138
+
139
+ response = Shipments.track(data, context=request, **carrier_filter)
140
+
141
+ return Response(
142
+ TrackingResponse(response).data,
143
+ status=(
144
+ status.HTTP_200_OK
145
+ if response.tracking is not None
146
+ else status.HTTP_404_NOT_FOUND
147
+ ),
148
+ )
149
+
150
+
151
+ router.urls.append(
152
+ path(
153
+ "proxy/tracking",
154
+ TrackingAPIView.as_view(),
155
+ name="get-tracking",
156
+ )
157
+ )
158
+ # Deprecated will be removed soon.
159
+ router.urls.append(
160
+ path(
161
+ "proxy/tracking/<str:carrier_name>/<str:tracking_number>",
162
+ TrackingAPI.as_view(),
163
+ name="shipment-tracking",
164
+ )
165
+ )
@@ -0,0 +1,27 @@
1
+ Metadata-Version: 2.4
2
+ Name: karrio_server_proxy
3
+ Version: 2025.5rc1
4
+ Summary: Multi-carrier shipping API Proxy module
5
+ Author-email: karrio <hello@karrio.io>
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/karrioapi/karrio
8
+ Classifier: Programming Language :: Python :: 3
9
+ Requires-Python: >=3.11
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: karrio_server_core
12
+
13
+ # karrio.server.proxy
14
+
15
+ This package is a module of the [karrio](https://pypi.org/project/karrio.server) universal shipping API.
16
+
17
+ ## Requirements
18
+
19
+ `Python 3.11+`
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ pip install karrio.server.proxy
25
+ ```
26
+
27
+ Check the [karrio docs](https://docs.karrio.io) to get started.
@@ -0,0 +1,22 @@
1
+ karrio/server/proxy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ karrio/server/proxy/admin.py,sha256=suMo4x8I3JBxAFBVIdE-5qnqZ6JAZV0FESABHOSc-vg,63
3
+ karrio/server/proxy/apps.py,sha256=jSzNhgTmq6Z5mIo-pv5jeEx2PJMI31oUGfBBLEO3p-M,99
4
+ karrio/server/proxy/models.py,sha256=Vjc0p2XbAPgE6HyTF6vll98A4eDhA5AvaQqsc4kQ9AQ,57
5
+ karrio/server/proxy/router.py,sha256=IBUR7rfBkdEHQzWxYOPcVSM8NBp3fte9G6Q5BVTUNNw,95
6
+ karrio/server/proxy/urls.py,sha256=DJFUFeaxOTyVNgu_A4opiX4-0gJlciRJNob-ScOkdV4,214
7
+ karrio/server/proxy/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ karrio/server/proxy/tests/__init__.py,sha256=m6Nms0Mg2SsrhNtWGC9Pr67qxpWos3WHipHfQZ6Zslw,263
9
+ karrio/server/proxy/tests/test_pickup.py,sha256=Z1P3a-ueLDkDPVnPEoPacHgtZXSgc6SCUYLpwv0DSzM,8817
10
+ karrio/server/proxy/tests/test_rating.py,sha256=ACc-9DnlND1eEg2QN_roeIG6kOeKSrlQVEtXrubeKyA,3151
11
+ karrio/server/proxy/tests/test_shipping.py,sha256=YG3uH5wL6bLEAO7iUQRsebKKuAFT23QegWRRyHgVOH0,10535
12
+ karrio/server/proxy/tests/test_tracking.py,sha256=aO4y6MqgANCGA2QN3a79ZxyAGfXcEXlKV6ghogGbO-w,2965
13
+ karrio/server/proxy/views/__init__.py,sha256=5W2I_z2WEgpnHzfrJWWMx0ptxGSGSHb3yO-ymYHggZQ,252
14
+ karrio/server/proxy/views/manifest.py,sha256=8O9H8iUUTpL0wPge0_j7vmEYGcaksUk_5bxBp9FNgjE,1793
15
+ karrio/server/proxy/views/pickup.py,sha256=GfmZBQMZSDDJKiHT-n3grIwgi02JMhnTQyaP7e4YcY8,4566
16
+ karrio/server/proxy/views/rating.py,sha256=7S2N6szPSjQsShnCgzPL8iZpibpw8jbaWgSY9DWXYQI,1721
17
+ karrio/server/proxy/views/shipping.py,sha256=gmO1OBVE8OgmyYIi_ksT_IARyqAeVKucUjMMiz_Vzyk,4459
18
+ karrio/server/proxy/views/tracking.py,sha256=HwCMinmiLsLuYyQtQpdmorFQ0WoNQyQ3uJ12_l6IwpQ,5227
19
+ karrio_server_proxy-2025.5rc1.dist-info/METADATA,sha256=D-e04IfxgPhkFTvaymOXcyaI73sLo1TXfoHvvvOivH8,680
20
+ karrio_server_proxy-2025.5rc1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
21
+ karrio_server_proxy-2025.5rc1.dist-info/top_level.txt,sha256=D1D7x8R3cTfjF_15mfiO7wCQ5QMtuM4x8GaPr7z5i78,12
22
+ karrio_server_proxy-2025.5rc1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ dist
2
+ karrio