Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions modules/connectors/ups/karrio/mappers/ups/proxy.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import typing
import datetime
import uuid
import karrio.lib as lib
import karrio.api.proxy as proxy
import karrio.core.errors as errors
Expand Down Expand Up @@ -94,20 +95,31 @@ def cancel_shipment(self, request: lib.Serializable) -> lib.Deserializable:
def get_tracking(self, request: lib.Serializable) -> lib.Deserializable[typing.List[typing.Tuple[str, dict]]]:
locale = self.settings.connection_config.locale.state or "en_US"
token = self.get_token()
transaction_source = "karrio-test" if self.settings.test_mode else "karrio-prod"

responses = lib.run_concurently(
lambda tracking_number: (
def fetch_tracking(tracking_number: str) -> typing.Tuple[str, typing.Any]:
trans_id = str(uuid.uuid4())

return (
tracking_number,
lib.request(
url=f"{self.settings.server_url}/api/track/v1/details/{tracking_number}?locale={locale}&returnSignature=true",
url=(
f"{self.settings.server_url}/api/track/v1/details/{tracking_number}"
f"?locale={locale}&returnSignature=true"
),
trace=self.trace_as("json"),
method="GET",
headers={
"authorization": f"Bearer {token}",
"content-Type": "application/json",
"transId": trans_id,
"transactionSrc": transaction_source,
},
),
),
)

responses = lib.run_concurently(
fetch_tracking,
request.serialize(),
)

Expand Down
5 changes: 5 additions & 0 deletions modules/connectors/ups/tests/ups/test_tracking.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import unittest
import uuid
from unittest.mock import patch
from karrio.core.utils import DP
from karrio.core.models import TrackingRequest
Expand All @@ -21,10 +22,14 @@ def test_get_tracking(self, http_mock):
karrio.Tracking.fetch(self.TrackingRequest).from_(gateway)

url = http_mock.call_args[1]["url"]
headers = http_mock.call_args[1]["headers"]
self.assertEqual(
url,
f"{gateway.settings.server_url}/api/track/v1/details/{self.TrackingRequest.tracking_numbers[0]}?locale=en_US&returnSignature=true",
)
self.assertEqual(headers["transactionSrc"], "karrio-prod")
self.assertTrue(headers["transId"])
uuid.UUID(headers["transId"])

def test_tracking_auth_error_parsing(self):
with patch("karrio.mappers.ups.proxy.lib.request") as mock:
Expand Down
17 changes: 17 additions & 0 deletions modules/core/karrio/server/core/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,23 @@ class TrackingData(serializers.Serializer):
required=True,
help_text="The tracking carrier",
)
carrier_id = serializers.CharField(
required=False,
allow_blank=False,
allow_null=True,
help_text=(
"Optional carrier connection identifier (connection id or carrier_id). "
"Useful when multiple connections exist for the same carrier."
),
)
test_mode = serializers.BooleanField(
required=False,
allow_null=True,
help_text=(
"Optional connection mode selector. When provided, tracking resolves "
"against carriers in the specified test/prod mode."
),
)
account_number = serializers.CharField(
required=False,
allow_blank=True,
Expand Down
28 changes: 28 additions & 0 deletions modules/manager/karrio/server/manager/tests/test_trackers.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,34 @@ def test_shipment_tracking_retry(self):
self.assertDictEqual(response_data, TRACKING_RESPONSE)
self.assertEqual(len(self.user.tracking_set.all()), 1)

def test_trackers_post_with_connection_selectors(self):
url = reverse("karrio.server.manager:trackers-list")
data = dict(
tracking_number="1Z12345E6205277936",
carrier_name="ups",
carrier_id="ups_package",
test_mode=True,
)

with (
patch(
"karrio.server.manager.serializers.tracking.Connections.first",
wraps=serializers.tracking.Connections.first,
) as first_mock,
patch("karrio.server.core.gateway.utils.identity") as mock,
):
mock.return_value = RETURNED_VALUE
response = self.client.post(url, data)

self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)
self.assertTrue(
any(
call.kwargs.get("carrier_id") == "ups_package"
and call.kwargs.get("test_mode") is True
for call in first_mock.call_args_list
)
)


class TestTrackersUpdate(APITestCase):
def setUp(self) -> None:
Expand Down
6 changes: 6 additions & 0 deletions modules/manager/karrio/server/manager/views/trackers.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ def post(self, request: Request):
# If a hub is specified, use the hub as carrier to track the package
"carrier_name": carrier_name,
}
# Respect explicit connection selectors from payload when present.
if data.get("carrier_id"):
carrier_filter["carrier_id"] = data["carrier_id"]
if data.get("test_mode") is not None:
# Preserve explicit False (prod) and True (test).
carrier_filter["test_mode"] = data["test_mode"]
data = {
**data,
"tracking_number": data["tracking_number"],
Expand Down
24 changes: 24 additions & 0 deletions modules/proxy/karrio/server/proxy/tests/test_tracking.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from rest_framework import status
from karrio.core.models import TrackingDetails, TrackingEvent
from karrio.server.core.tests import APITestCase
from karrio.server.core.gateway import Shipments


class TestTracking(APITestCase):
Expand All @@ -19,6 +20,29 @@ def test_tracking_shipment(self):
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertDictEqual(response_data, TRACKING_RESPONSE)

def test_tracking_shipment_with_connection_selectors(self):
url = reverse("karrio.server.proxy:get-tracking")
data = dict(
tracking_number="1Z12345E6205277936",
carrier_name="ups",
carrier_id="ups_package",
test_mode=True,
)

with (
patch(
"karrio.server.proxy.views.tracking.Shipments.track",
wraps=Shipments.track,
) as track_mock,
patch("karrio.server.core.gateway.utils.identity") as mock,
):
mock.return_value = RETURNED_VALUE
response = self.client.post(f"{url}", data)

self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(track_mock.call_args.kwargs.get("carrier_id"), "ups_package")
self.assertIs(track_mock.call_args.kwargs.get("test_mode"), True)


RETURNED_VALUE = [
[
Expand Down
6 changes: 6 additions & 0 deletions modules/proxy/karrio/server/proxy/views/tracking.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ def post(self, request: Request):
query.get("hub") if "hub" in query else data["carrier_name"]
),
}
# Respect explicit connection selectors from payload when present.
if data.get("carrier_id"):
carrier_filter["carrier_id"] = data["carrier_id"]
if data.get("test_mode") is not None:
# Preserve explicit False (prod) and True (test).
carrier_filter["test_mode"] = data["test_mode"]
data = {
**data,
"tracking_numbers": [data["tracking_number"]],
Expand Down