tracking: support explicit carrier_id and test_mode selection#976
tracking: support explicit carrier_id and test_mode selection#976HansDaigle wants to merge 5474 commits intokarrioapi:mainfrom
Conversation
Remove custom async wrappers and logic from mapper.py to strictly follow the Karrio mapper template. The mapper should only contain simple delegation methods that call provider functions. Changes: - Removed create_shipment(), _create_shipment() async wrapper methods - Removed get_tracking(), _get_tracking() async wrapper methods - Removed custom response handling logic from parse_tracking_response() - Updated tracking provider to handle multiple responses from proxy - Mapper now only contains pure delegation methods as per template This follows the template at: github.com/karrioapi/karrio/.../templates/sdk.py
Add pickup preview sheet (side panel) matching the shipment detail sheet pattern. Includes pickup detail view with header, status badge, details sidebar (carrier, confirmation, dates, time window, location), pickup address, parcels, related shipments table with tracker status, tracking records from related shipments, metadata viewer, and activity timeline with API logs and system events. Expand GET_PICKUP GraphQL query to include tracker data on related shipments. Add View details menu option and clickable table rows on the pickups list page.
Add tests for carrier-agnostic pickup scheduling, status transitions, and pickup lifecycle event handling.
Rename CARRIER_CONNECTION_ARCHITECTURE.md to use hyphenated casing (CARRIER-CONNECTION-ARCHITECTURE.md) for consistency.
…nt KeyError when key is missing
Add a dedicated tracker detail page at /trackers/[id] with tracking events timeline, shipment link, metadata editor, and ActivityTimeline for API logs, traces, and system events. Augment the tracker preview sheet with a condensed activity section and "View all" navigation. - Create TrackerComponent with entity-based log/event filtering - Add stacked layout mode to ActivityTimeline for inline detail viewing - Add condensed prop to ActivityTimeline for compact rendering - Fix infinite re-render in trackers list (searchParams object ref) - Fix infinite re-render in trackers filter (variables object ref) - Fix preview sheet showing unrelated logs (hooks initialized before tracker selection)
…ents Stabilize useEffect dependencies across all list pages and filter components to prevent maximum update depth errors. Replace object reference dependencies with stable string representations. - Use searchParams.toString() instead of searchParams object in Shipments, Pickups, Orders, Manifests, and Workflows list pages - Use JSON.stringify(variables) instead of variables object in shipments-filter and orders-filter components
Replace jinja2.Template() with jinja2.sandbox.SandboxedEnvironment in the document generator and workflow automation engine to prevent Server-Side Template Injection allowing authenticated users to execute arbitrary Python code via crafted document templates. Reported by: i0.rs (Georgios Tsimpidas, Edward Passenidis)
- Add weight range per-service scoping with inline CRUD - Add service rate detail view with virtual rows - Add CSV import/export preview for rate sheets - Add zone/surcharge editor dialogs - Enhance carrier connector plugins with services.csv data - Add authentication test fixtures for carriers - Add caching tests and improvements - Add pickup capability migration for dhl_parcel_de - Sync Redis configuration improvements Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
[patch] 2026.1.5
|
@HansDaigle is attempting to deploy a commit to the karrio Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
Review
The feature direction is right. When a user has multiple connections for the same carrier — two DHL accounts, one domestic and one international — tracking currently has no way to pin to a specific connection at call time. Shipping, pickups, and rates all support carrier_id selection already, so this is a genuine consistency gap and worth closing.
That said, there are two things to address before this can land.
Drop test_mode from TrackingData
test_mode is already handled by the API token and auth context. When an API key is scoped to test mode, request.test_mode is set to True, and Connections.first() already reads it:
test_mode = list_filter.get("test_mode") or getattr(context, "test_mode", None)Adding it to the request body creates a second control surface for the same thing, with ambiguous precedence and a real security implication: the current implementation lets the body value win, which means a production API key with test_mode=True in the payload silently resolves against test-mode carriers. That's backwards. The API token and the X-Karrio-Test header are the right mechanisms — the request body shouldn't override authentication context.
Move the carrier_id forwarding into the serializer
For the POST /v1/trackers flow, you've put the forwarding in the view:
if data.get("carrier_id"):
carrier_filter["carrier_id"] = data["carrier_id"]But TrackingSerializer already declares carrier_id as a field — it lives in validated_data. The view shouldn't need to know that carrier_id exists and manually forward it; the serializer's own create() should handle it:
carrier_filter = {
**validated_data["carrier_filter"],
**(
{"carrier_id": validated_data["carrier_id"]}
if validated_data.get("carrier_id")
else {}
),
}This keeps the view lean and the behaviour self-contained — consistent with how TrackingSerializer already manages its own carrier_filter assembly. The proxy endpoint (/v1/proxy/tracking) is a different case since it calls Shipments.track directly, so view-level forwarding is correct there.
Rebase
This branch has diverged heavily from main — the 4000+ file diff is all drift. The manager serializer and proxy view have both changed substantially since this was opened. A rebase before the next push will surface any real conflicts and make the actual change visible.
Once rebased, the functional diff should be small: carrier_id on TrackingData, the forwarding in the proxy view, and the serializer-level merge in TrackingSerializer.create(). That's a clean, focused change with a clear path to merge.
Summary
carrier_idandtest_modetoTrackingDatafor tracking POST APIs.POST /v1/proxy/trackingPOST /v1/trackersWhy
When multiple connections exist for the same carrier, tracking should be able to deterministically target a specific connection/mode, consistent with shipping connection selection behavior.
Tests
carrier_idandtest_modeare forwarded toShipments.track.Connections.firstin serializer flow.Validation
py_compilefor changed files.