Skip to content

tracking: support explicit carrier_id and test_mode selection#976

Open
HansDaigle wants to merge 5474 commits intokarrioapi:mainfrom
HansDaigle:fix/tracking-carrier-selection
Open

tracking: support explicit carrier_id and test_mode selection#976
HansDaigle wants to merge 5474 commits intokarrioapi:mainfrom
HansDaigle:fix/tracking-carrier-selection

Conversation

@HansDaigle
Copy link
Copy Markdown
Contributor

Summary

  • Add carrier_id and test_mode to TrackingData for tracking POST APIs.
  • Forward those selectors to carrier resolution in:
    • POST /v1/proxy/tracking
    • POST /v1/trackers

Why

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

  • Added proxy tracking test to assert carrier_id and test_mode are forwarded to Shipments.track.
  • Added manager trackers test to assert selectors reach Connections.first in serializer flow.

Validation

  • Syntax checked with py_compile for changed files.

claude and others added 30 commits December 24, 2025 12:47
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
danh91 and others added 24 commits February 4, 2026 21:11
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.
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>
@vercel
Copy link
Copy Markdown

vercel Bot commented Feb 23, 2026

@HansDaigle is attempting to deploy a commit to the karrio Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Copy Markdown
Member

@danh91 danh91 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants