From 5d79ac5e570f77c1e822733b3f9fb8c631405b87 Mon Sep 17 00:00:00 2001 From: Ansh Dev Nagar Date: Wed, 4 Mar 2026 10:56:44 +0530 Subject: [PATCH 1/9] docs: add carrier testing report for MyDHL --- carrier-testing/mydhl.md | 238 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 238 insertions(+) create mode 100644 carrier-testing/mydhl.md diff --git a/carrier-testing/mydhl.md b/carrier-testing/mydhl.md new file mode 100644 index 0000000000..f63603862a --- /dev/null +++ b/carrier-testing/mydhl.md @@ -0,0 +1,238 @@ +# MyDHL Express — Carrier Testing + +## Metadata + +| Field | Value | +|----------------------------|--------------------------------------| +| **Carrier Name** | `mydhl` | +| **Carrier Display Name** | MyDHL Express | +| **Environment** | Production (`express.api.dhl.com/mydhlapi`) | +| **Connection Credentials** | DE production account configured in Dashboard | +| **Last Tested** | 2026-03-04 | + +--- + +## 1. Connection Setup + +> Verify the carrier can be connected and authenticated. MyDHL uses Basic Authentication with `username`, `password`, and `account_number`. + +- [x] Carrier connection created successfully in Dashboard +- [x] Authentication succeeds (no credential errors) +- [x] Connection appears in carrier list + +**Notes:** `account_number` (DHL billing number) must be configured — without it, rate/shipment requests fail with `"required key [number] not found"`. + +--- + +## 2. Rating / Rate Fetching + +> Test rate retrieval for shipments. MyDHL provides a **live rate endpoint** via `/rates`. + +**Rate Type:** `Live API Endpoint` + +### Live API Endpoint: +- [x] Fetch domestic rates successfully +- [x] Fetch international rates successfully +- [x] Rates returned for all expected services + +**DE Domestic:** 6 services returned in EUR — EXPRESS EASY (19.29), EXPRESS DOMESTIC (27.26), EXPRESS DOMESTIC 12:00 (33.18), EXPRESS DOMESTIC 10:30 (45.00), EXPRESS DOMESTIC 9:00 (68.65), MEDICAL EXPRESS DOMESTIC (74.98). + +**DE→US International:** 5 services returned in EUR — EXPRESS EASY (112.01), EXPRESS WORLDWIDE (170.12), EXPRESS 12:00 (176.64), EXPRESS 10:30 (189.69), MEDICAL EXPRESS (206.53). + +**Notes:** Tested with temporary Bug 1 workaround applied (fix reverted after testing). Some service codes in the response don't match the `ShippingService` enum (see Bug 4). + +--- + +## 3. Shipping / Shipment Creation + +> Test creating shipments and generating labels via `/shipments`. + +**Supported:** `Yes` + +### Basic Shipment +- [x] Create domestic shipment with default service +- [ ] Label generated and downloadable as PDF (Bug 3 — label not extracted) +- [x] Tracking number returned in response +- [x] Shipment appears in shipment list + +### Service Coverage +- [ ] Create shipment with each available service (list services tested below) + +| Service Code | Service Name | Product Code | Result | +|---|---|---|---| +| mydhl_express_worldwide_b2c | EXPRESS EASY | 7 | Pass (tracking returned, no label) | +| mydhl_express_domestic | EXPRESS DOMESTIC | N | Fail — `"Requested product(s) not available at origin"` | + +### Multi-Piece Shipment +- [ ] Create shipment with 2+ parcels (Blocked — Bugs 1-2 require fixes first) + +### International Shipment (if applicable) +- [ ] Create international shipment with customs info (Blocked — Bugs 1-2 require fixes first) + +**Notes:** Tested with temporary Bug 1 + Bug 2 workarounds applied (fixes reverted after testing). Service mapping in response shows `service: "mydhl"` instead of actual service name (Bug 5). Express Domestic (N) not available for DE origin with this account — use EXPRESS EASY (7) instead. + +--- + +## 4. Label + +> Test label output options. MyDHL supports PDF, ZPL, LP2, and EPL label formats. + +**Supported:** `Yes` + +- [ ] Label downloads as PDF (Bug 3 — label content empty) +- [ ] Label format matches requested format +- [ ] Label contains correct shipper and recipient info + +**Available label formats:** `PDF`, `ZPL`, `LP2`, `EPL` + +**Notes:** DHL returns label data (7144 chars base64 PDF confirmed in raw response) but it's not extracted into the shipment response. See Bug 3. + +--- + +## 5. Shipment Cancellation + +> Test cancelling/voiding shipments. + +**Supported:** `Yes` (via Karrio resource management) + +- [x] Cancel a newly created shipment +- [x] Shipment status updates to cancelled + +**Notes:** Tested with temporary Bug 1 + Bug 2 workarounds applied (fixes reverted after testing). Cancelled shipment `shp_e405009e929e483299ba69362caa2b04` successfully. Status updated to cancelled via Karrio resource management. + +--- + +## 6. Tracking + +> Test tracking shipment status via `/tracking`. + +**Supported:** `Yes` + +- [x] Track a shipment by tracking number +- [x] Tracking events returned with timestamps +- [x] Tracking status reflects current state + +**Notes:** Tested with temporary Bug 1 + Bug 2 workarounds applied (fixes reverted after testing). Tracked shipment `3627506190` — returned `pending` status with "Label created" event and timestamp. + +--- + +## 7. Pickup Scheduling + +> Test scheduling and managing pickups via `/pickups`. + +**Supported:** `Yes` + +### Schedule Pickup +- [ ] Schedule pickup with valid address and date (Blocked — Bug 2 + Bug 6) +- [ ] Confirmation number returned +- [ ] Pickup appears in pickup list + +### Cancel Pickup +- [ ] Cancel a scheduled pickup +- [ ] Pickup status updates to cancelled + +**Notes:** Attempted but blocked — Bug 2 (invalid typeCode `YP` in `pickup/create.py:159`) causes request to fail, and Bug 6 (missing `additionalDetails`) hides the actual DHL error details. + +--- + +## 8. Return Shipment + +> Test return shipment creation. + +**Supported:** `Yes` + +- [ ] Create return shipment (Blocked — Bugs 1-2 require fixes first) +- [ ] Return label generated +- [ ] Return tracking number provided + +**Notes:** Not tested — blocked by Bug 1 (date parsing) and Bug 2 (invalid typeCode) which must be fixed before return shipments can be created. + +--- + +## Shipping Options Reference + +> Key shipping options available for testing. + +| Option | Type | Description | +|---|---|---| +| `mydhl_saturday_delivery` | bool | Saturday delivery (AA) | +| `mydhl_hold_for_collection` | bool | Hold at service point (LX) | +| `mydhl_duty_tax_paid` | bool | DTP — Duty/Tax Paid (DD) | +| `mydhl_shipment_insurance` | float | Insurance value (II) | +| `mydhl_dangerous_goods` | bool | Dangerous goods (HE) | +| `mydhl_direct_signature` | bool | Direct signature required (SF) | +| `mydhl_paperless_trade` | bool | Paperless trade (WY) | +| `mydhl_gogreen_climate_neutral` | bool | GoGreen Carbon Neutral (EE) | + +--- + +## Edge Cases & Error Handling + +> General robustness checks. + +- [ ] Invalid credentials show clear error message +- [ ] Missing required fields return descriptive validation errors +- [ ] Duplicate shipment creation handled + +**Notes:** Error responses from DHL include `additionalDetails` array with specific validation errors, but the error parser doesn't capture them (see Bug 6). + +--- + +## Bugs Found + +> Bugs discovered during testing. + +### Bug 1: Rate and shipment requests fail with date parsing error +**Impact:** All rate fetching and shipment creation fails without workaround. +**Root Cause:** `lib.fdatetime` called without `current_format` — defaults to `"%Y-%m-%d %H:%M:%S"` but server provides date-only `"%Y-%m-%d"` string. Shipment create also passes output format as positional arg to `current_format`. +**Files:** `rate.py:137`, `shipment/create.py:174` +**Status:** Open + +### Bug 2: Shipment creation fails with invalid package typeCode +**Impact:** All shipment creation fails with `"YP is not a valid enum value"`. +**Root Cause:** `PackagingType` enum uses codes (`FLY`, `YP`, `JB`, `JJ`, `3`) that don't exist in the DHL API spec. Valid codes are: `1CE, 2BC, 2BP, 2BX, 3BX, 4BX, 5BX, 6BX, 7BX, 8BX, CE1, TBL, TBS, WB1, WB2, WB3, WB6, XPD`. Also, `typeCode` is optional — omitting it uses customer packaging by default. +**Files:** `units.py:15-41`, `shipment/create.py:266-268`, `pickup/create.py:159` +**Status:** Open + +### Bug 3: Label content not extracted from shipment response +**Impact:** Shipments are created successfully but label is empty in the response. +**Root Cause:** DHL returns label data (confirmed 7144 chars base64 PDF in raw response) but the `_extract_details` parser returns empty label. Likely a `jstruct.JList` deserialization issue with the `documents` array. +**Files:** `shipment/create.py:46-50` +**Status:** Open + +### Bug 4: Service code mapping mismatches (widespread) +**Impact:** Many rate responses show wrong service names. At least 9 product codes are incorrect or missing from DHL spec reference data. +**Root Cause:** `ShippingService` enum maps product codes to service names that don't match the DHL API v3.1.1 spec. Verified mismatches: `Y` (not in spec, mapped as EXPRESS 9:00), `M` (not in spec, mapped as GLOBALMAIL BUSINESS), `K` (spec: EXPRESS 9:00, mapped as EXPRESS 10:30), `8` (not in spec, mapped as EXPRESS EASY — should be `7`), `Q` (not in spec, mapped as MEDICAL EXPRESS — should be `C`), `R` (spec: GLOBALMAIL, mapped as SPRINTLINE), `G` (spec: ECONOMY SELECT DOMESTIC, mapped as GLOBALMAIL), `E` (not in spec, mapped as BREAKBULK EXPRESS — should be `B`), `F` (not in spec, mapped as EXPRESS FREIGHT). +**Files:** `units.py:44-82` +**Status:** Open + +### Bug 5: Service name in shipment response always shows carrier name +**Impact:** Created shipments show `service: "mydhl"` instead of the actual service like `mydhl_express_worldwide_b2c`. +**Root Cause:** `_extract_details` sets `service=settings.carrier_name` instead of mapping the product code from the response. +**Files:** `shipment/create.py:70` +**Status:** Open + +### Bug 6: Error responses missing additionalDetails +**Impact:** DHL validation errors show `"Multiple problems found, see Additional Details"` but the actual details are not included in the error response. +**Root Cause:** `ErrorResponseType` schema doesn't include `additionalDetails` field, and error parser doesn't pass it through. +**Files:** `error_response.py`, `error.py` +**Status:** Open + +--- + +## Summary + +| Feature | Status | +|------------------|---------| +| Connection Setup | Pass | +| Rating | Pass (with Bug 1 fix) | +| Shipping | Partial (Bugs 1-3) | +| Label | Fail (Bug 3) | +| Cancellation | Pass | +| Tracking | Pass | +| Pickup | Blocked (Bugs 2, 6) | +| Return Shipment | Blocked (Bugs 1-2) | + +**Overall Result:** Blocked — 6 bugs found, fixes needed before full testing + +**Additional Notes:** Tested with DE production credentials against `express.api.dhl.com/mydhlapi`. Rating works after Bug 1 workaround. Shipment creation works (tracking number returned) after Bug 1+2 workarounds, but label extraction is broken (Bug 3). Tracking and cancellation work correctly. Pickup blocked by invalid typeCode (Bug 2) and hidden error details (Bug 6). Return shipments and multi-piece/international shipping blocked pending bug fixes. From b731cbc5df117355a9082015b4dd2322dbbc0034 Mon Sep 17 00:00:00 2001 From: Ansh Dev Nagar Date: Thu, 5 Mar 2026 09:53:50 +0530 Subject: [PATCH 2/9] fix(mydhl): fix date parsing in rate and shipment requests and dimension null check --- modules/connectors/mydhl/karrio/providers/mydhl/rate.py | 9 +++++---- .../mydhl/karrio/providers/mydhl/shipment/create.py | 3 ++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/modules/connectors/mydhl/karrio/providers/mydhl/rate.py b/modules/connectors/mydhl/karrio/providers/mydhl/rate.py index 935cec699a..3d08795e7a 100644 --- a/modules/connectors/mydhl/karrio/providers/mydhl/rate.py +++ b/modules/connectors/mydhl/karrio/providers/mydhl/rate.py @@ -136,6 +136,7 @@ def rate_request( ) planned_date = lib.fdatetime( options.shipment_date.state or datetime.datetime.now(), + current_format="%Y-%m-%d", output_format="%Y-%m-%dT%H:%M:%S GMT+00:00", ) @@ -181,11 +182,11 @@ def rate_request( weight=package.weight.value, dimensions=( mydhl_req.DimensionsType( - length=int(package.length.value) if package.length else None, - width=int(package.width.value) if package.width else None, - height=int(package.height.value) if package.height else None, + length=int(package.length.value) if package.length.value else None, + width=int(package.width.value) if package.width.value else None, + height=int(package.height.value) if package.height.value else None, ) - if any([package.length, package.width, package.height]) + if any([package.length.value, package.width.value, package.height.value]) else None ), ) diff --git a/modules/connectors/mydhl/karrio/providers/mydhl/shipment/create.py b/modules/connectors/mydhl/karrio/providers/mydhl/shipment/create.py index 72d7273ae0..2689159cf7 100644 --- a/modules/connectors/mydhl/karrio/providers/mydhl/shipment/create.py +++ b/modules/connectors/mydhl/karrio/providers/mydhl/shipment/create.py @@ -173,7 +173,8 @@ def shipment_request( # Incoterm and planned shipping date planned_date = lib.fdatetime( options.shipment_date.state or datetime.datetime.now(), - "%Y-%m-%dT%H:%M:%S GMT+00:00", + current_format="%Y-%m-%d", + output_format="%Y-%m-%dT%H:%M:%S GMT+00:00", ) planned_ship_date = lib.fdate( options.shipment_date.state or datetime.datetime.now() From 285b707718b1289ad565ad6b89ebab3b13c02a86 Mon Sep 17 00:00:00 2001 From: Ansh Dev Nagar Date: Thu, 5 Mar 2026 10:04:07 +0530 Subject: [PATCH 3/9] fix(mydhl): add additionalDetails to error response schema and parser --- modules/connectors/mydhl/karrio/providers/mydhl/error.py | 1 + modules/connectors/mydhl/karrio/schemas/mydhl/error_response.py | 1 + 2 files changed, 2 insertions(+) diff --git a/modules/connectors/mydhl/karrio/providers/mydhl/error.py b/modules/connectors/mydhl/karrio/providers/mydhl/error.py index 0e36b15aa6..032536d3ed 100644 --- a/modules/connectors/mydhl/karrio/providers/mydhl/error.py +++ b/modules/connectors/mydhl/karrio/providers/mydhl/error.py @@ -30,6 +30,7 @@ def parse_error_response( **kwargs, "instance": error.instance, "title": error.title, + "additionalDetails": error.additionalDetails, } ), ) diff --git a/modules/connectors/mydhl/karrio/schemas/mydhl/error_response.py b/modules/connectors/mydhl/karrio/schemas/mydhl/error_response.py index 4b40603126..77369ad6da 100644 --- a/modules/connectors/mydhl/karrio/schemas/mydhl/error_response.py +++ b/modules/connectors/mydhl/karrio/schemas/mydhl/error_response.py @@ -9,4 +9,5 @@ class ErrorResponseType: detail: typing.Optional[str] = None title: typing.Optional[str] = None message: typing.Optional[str] = None + additionalDetails: typing.Optional[typing.List[str]] = None status: typing.Optional[int] = None From 5d1026441ea70c98254968ada63b4b7593c6498a Mon Sep 17 00:00:00 2001 From: Ansh Dev Nagar Date: Thu, 5 Mar 2026 10:45:23 +0530 Subject: [PATCH 4/9] fix(mydhl): replace invalid PackagingType codes with DHL API spec values and make typeCode optional --- .../karrio/providers/mydhl/pickup/create.py | 6 +++- .../karrio/providers/mydhl/pickup/update.py | 6 +++- .../karrio/providers/mydhl/shipment/create.py | 8 +++-- .../mydhl/karrio/providers/mydhl/units.py | 31 ++++++++++++------- 4 files changed, 34 insertions(+), 17 deletions(-) diff --git a/modules/connectors/mydhl/karrio/providers/mydhl/pickup/create.py b/modules/connectors/mydhl/karrio/providers/mydhl/pickup/create.py index 7404262f58..0f28607108 100644 --- a/modules/connectors/mydhl/karrio/providers/mydhl/pickup/create.py +++ b/modules/connectors/mydhl/karrio/providers/mydhl/pickup/create.py @@ -156,7 +156,11 @@ def pickup_request( unitOfMeasurement="metric", packages=[ pickup_req.PackageType( - typeCode=provider_units.PackagingType.map(package.packaging_type or "your_packaging").value, + typeCode=lib.identity( + provider_units.PackagingType.map(package.packaging_type).value + if package.packaging_type + else None + ), weight=package.weight.value, dimensions=pickup_req.DimensionsType( length=package.length.value, diff --git a/modules/connectors/mydhl/karrio/providers/mydhl/pickup/update.py b/modules/connectors/mydhl/karrio/providers/mydhl/pickup/update.py index 694b5d4583..b27311261a 100644 --- a/modules/connectors/mydhl/karrio/providers/mydhl/pickup/update.py +++ b/modules/connectors/mydhl/karrio/providers/mydhl/pickup/update.py @@ -146,7 +146,11 @@ def pickup_update_request( unitOfMeasurement="metric", packages=[ pickup_req.PackageType( - typeCode=provider_units.PackagingType.map(package.packaging_type or "your_packaging").value, + typeCode=lib.identity( + provider_units.PackagingType.map(package.packaging_type).value + if package.packaging_type + else None + ), weight=package.weight.value, dimensions=pickup_req.DimensionsType( length=package.length.value, diff --git a/modules/connectors/mydhl/karrio/providers/mydhl/shipment/create.py b/modules/connectors/mydhl/karrio/providers/mydhl/shipment/create.py index 2689159cf7..08b2ea9ab9 100644 --- a/modules/connectors/mydhl/karrio/providers/mydhl/shipment/create.py +++ b/modules/connectors/mydhl/karrio/providers/mydhl/shipment/create.py @@ -263,9 +263,11 @@ def shipment_request( content=mydhl_req.ContentType( packages=[ mydhl_req.PackageType( - typeCode=provider_units.PackagingType.map( - package.packaging_type or "your_packaging" - ).value, + typeCode=lib.identity( + provider_units.PackagingType.map(package.packaging_type).value + if package.packaging_type + else None + ), weight=package.weight.value, dimensions=lib.identity( mydhl_req.DimensionsType( diff --git a/modules/connectors/mydhl/karrio/providers/mydhl/units.py b/modules/connectors/mydhl/karrio/providers/mydhl/units.py index d821a72343..d698a989aa 100644 --- a/modules/connectors/mydhl/karrio/providers/mydhl/units.py +++ b/modules/connectors/mydhl/karrio/providers/mydhl/units.py @@ -13,32 +13,39 @@ class PackagingType(lib.StrEnum): - """DHL Express packaging types (typeCode values).""" + """DHL Express packaging types (typeCode values). + + From DHL API spec v3.1.1 — typeCode is optional; omitting it + defaults to customer packaging. + """ # DHL branded packaging - mydhl_flyer = "FLY" - mydhl_box_2 = "2BC" + mydhl_card_envelope_imperial = "1CE" + mydhl_box_2_cube = "2BC" + mydhl_box_2_pizza = "2BP" + mydhl_box_2_shoe = "2BX" mydhl_box_3 = "3BX" mydhl_box_4 = "4BX" mydhl_box_5 = "5BX" mydhl_box_6 = "6BX" mydhl_box_7 = "7BX" mydhl_box_8 = "8BX" - mydhl_express_envelope = "3" - mydhl_jumbo_box = "JB" - mydhl_jumbo_box_junior = "JJ" - - # Customer packaging - mydhl_customer_packaging = "YP" + mydhl_card_envelope = "CE1" + mydhl_tube_large = "TBL" + mydhl_tube_small = "TBS" + mydhl_bottle_box_1 = "WB1" + mydhl_bottle_box_2 = "WB2" + mydhl_bottle_box_3 = "WB3" + mydhl_bottle_box_6 = "WB6" + mydhl_express_envelope = "XPD" """ Unified Packaging type mapping """ envelope = mydhl_express_envelope - pak = mydhl_flyer - tube = mydhl_box_2 + pak = mydhl_card_envelope + tube = mydhl_tube_small small_box = mydhl_box_3 medium_box = mydhl_box_5 large_box = mydhl_box_8 - your_packaging = mydhl_customer_packaging class ShippingService(lib.StrEnum): From 83f7ed419821defc72cf9583b77279f8a0d293b1 Mon Sep 17 00:00:00 2001 From: Ansh Dev Nagar Date: Thu, 5 Mar 2026 15:33:00 +0530 Subject: [PATCH 5/9] fix(mydhl): correct ShippingService product codes and services.csv to match DHL API spec --- .../mydhl/karrio/providers/mydhl/units.py | 31 +++++++------------ 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/modules/connectors/mydhl/karrio/providers/mydhl/units.py b/modules/connectors/mydhl/karrio/providers/mydhl/units.py index d698a989aa..d821a72343 100644 --- a/modules/connectors/mydhl/karrio/providers/mydhl/units.py +++ b/modules/connectors/mydhl/karrio/providers/mydhl/units.py @@ -13,39 +13,32 @@ class PackagingType(lib.StrEnum): - """DHL Express packaging types (typeCode values). - - From DHL API spec v3.1.1 — typeCode is optional; omitting it - defaults to customer packaging. - """ + """DHL Express packaging types (typeCode values).""" # DHL branded packaging - mydhl_card_envelope_imperial = "1CE" - mydhl_box_2_cube = "2BC" - mydhl_box_2_pizza = "2BP" - mydhl_box_2_shoe = "2BX" + mydhl_flyer = "FLY" + mydhl_box_2 = "2BC" mydhl_box_3 = "3BX" mydhl_box_4 = "4BX" mydhl_box_5 = "5BX" mydhl_box_6 = "6BX" mydhl_box_7 = "7BX" mydhl_box_8 = "8BX" - mydhl_card_envelope = "CE1" - mydhl_tube_large = "TBL" - mydhl_tube_small = "TBS" - mydhl_bottle_box_1 = "WB1" - mydhl_bottle_box_2 = "WB2" - mydhl_bottle_box_3 = "WB3" - mydhl_bottle_box_6 = "WB6" - mydhl_express_envelope = "XPD" + mydhl_express_envelope = "3" + mydhl_jumbo_box = "JB" + mydhl_jumbo_box_junior = "JJ" + + # Customer packaging + mydhl_customer_packaging = "YP" """ Unified Packaging type mapping """ envelope = mydhl_express_envelope - pak = mydhl_card_envelope - tube = mydhl_tube_small + pak = mydhl_flyer + tube = mydhl_box_2 small_box = mydhl_box_3 medium_box = mydhl_box_5 large_box = mydhl_box_8 + your_packaging = mydhl_customer_packaging class ShippingService(lib.StrEnum): From 1007af93b44ca942adae105ae4167e04712092aa Mon Sep 17 00:00:00 2001 From: Ansh Dev Nagar Date: Thu, 5 Mar 2026 16:01:29 +0530 Subject: [PATCH 6/9] fix(mydhl): resolve service name in shipment response using request context --- modules/connectors/mydhl/karrio/mappers/mydhl/proxy.py | 2 +- .../mydhl/karrio/providers/mydhl/shipment/create.py | 8 ++++++-- modules/connectors/mydhl/tests/mydhl/test_shipment.py | 1 - 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/modules/connectors/mydhl/karrio/mappers/mydhl/proxy.py b/modules/connectors/mydhl/karrio/mappers/mydhl/proxy.py index 10e13eefee..092ad29446 100644 --- a/modules/connectors/mydhl/karrio/mappers/mydhl/proxy.py +++ b/modules/connectors/mydhl/karrio/mappers/mydhl/proxy.py @@ -68,7 +68,7 @@ def create_shipment(self, request: lib.Serializable) -> lib.Deserializable[str]: return lib.Deserializable( shipment_response, lib.to_dict, - dict(paperless_response=paperless_response), + dict(**request.ctx, paperless_response=paperless_response), ) def get_tracking(self, request: lib.Serializable) -> lib.Deserializable[str]: diff --git a/modules/connectors/mydhl/karrio/providers/mydhl/shipment/create.py b/modules/connectors/mydhl/karrio/providers/mydhl/shipment/create.py index 08b2ea9ab9..e87838503a 100644 --- a/modules/connectors/mydhl/karrio/providers/mydhl/shipment/create.py +++ b/modules/connectors/mydhl/karrio/providers/mydhl/shipment/create.py @@ -29,6 +29,7 @@ def parse_shipment_response( _extract_details( lib.to_object(mydhl_res.ShipmentResponseType, response), settings, + ctx=_response.ctx, ) if response.get("status") is None and response.get("shipmentTrackingNumber") is not None @@ -41,6 +42,7 @@ def parse_shipment_response( def _extract_details( shipment: mydhl_res.ShipmentResponseType, settings: provider_utils.Settings, + ctx: dict = None, ) -> models.ShipmentDetails: tracking_number = str(shipment.shipmentTrackingNumber or "") label_doc = next( @@ -67,7 +69,9 @@ def _extract_details( models.RateDetails( carrier_id=settings.carrier_id, carrier_name=settings.carrier_name, - service=settings.carrier_name, + service=provider_units.ShippingService.map( + (ctx or {}).get("service") + ).name_or_key, total_charge=lib.to_money(shipment_charge.price), currency=shipment_charge.priceCurrency, extra_charges=[ @@ -373,5 +377,5 @@ def shipment_request( shipment=lib.to_dict(req["shipment"]), paperless=lib.to_dict(req["paperless"]) if req.get("paperless") else None, ), - dict(is_paperless=is_paperless), + dict(is_paperless=is_paperless, service=payload.service), ) diff --git a/modules/connectors/mydhl/tests/mydhl/test_shipment.py b/modules/connectors/mydhl/tests/mydhl/test_shipment.py index 0bb071259b..838d1dfc62 100644 --- a/modules/connectors/mydhl/tests/mydhl/test_shipment.py +++ b/modules/connectors/mydhl/tests/mydhl/test_shipment.py @@ -137,7 +137,6 @@ def test_parse_error_response(self): "content": { "packages": [ { - "typeCode": "YP", "weight": 5.0, "dimensions": {"length": 25, "width": 20, "height": 15} } From dcc4e937289984862da9e271f56c6fe5ea04baf3 Mon Sep 17 00:00:00 2001 From: Ansh Dev Nagar Date: Thu, 5 Mar 2026 21:04:47 +0530 Subject: [PATCH 7/9] fix: mydhl pickup creation fails with extraneous countryName key --- modules/connectors/mydhl/karrio/providers/mydhl/pickup/create.py | 1 - modules/connectors/mydhl/karrio/providers/mydhl/pickup/update.py | 1 - modules/connectors/mydhl/tests/mydhl/test_pickup.py | 1 - 3 files changed, 3 deletions(-) diff --git a/modules/connectors/mydhl/karrio/providers/mydhl/pickup/create.py b/modules/connectors/mydhl/karrio/providers/mydhl/pickup/create.py index 0f28607108..072f1bf5b1 100644 --- a/modules/connectors/mydhl/karrio/providers/mydhl/pickup/create.py +++ b/modules/connectors/mydhl/karrio/providers/mydhl/pickup/create.py @@ -138,7 +138,6 @@ def pickup_request( addressLine2=address.address_line2, countyName=address.suburb, provinceName=address.state_name, - countryName=address.country_name, ), contactInformation=pickup_req.ContactInformationType( email=address.email, diff --git a/modules/connectors/mydhl/karrio/providers/mydhl/pickup/update.py b/modules/connectors/mydhl/karrio/providers/mydhl/pickup/update.py index b27311261a..25d59326a4 100644 --- a/modules/connectors/mydhl/karrio/providers/mydhl/pickup/update.py +++ b/modules/connectors/mydhl/karrio/providers/mydhl/pickup/update.py @@ -128,7 +128,6 @@ def pickup_update_request( addressLine2=address.address_line2, countyName=address.suburb, provinceName=address.state_name, - countryName=address.country_name, ), contactInformation=pickup_req.ContactInformationType( email=address.email, diff --git a/modules/connectors/mydhl/tests/mydhl/test_pickup.py b/modules/connectors/mydhl/tests/mydhl/test_pickup.py index fed7e36c51..343a1fd1d4 100644 --- a/modules/connectors/mydhl/tests/mydhl/test_pickup.py +++ b/modules/connectors/mydhl/tests/mydhl/test_pickup.py @@ -123,7 +123,6 @@ def test_parse_error_response(self): "addressLine1": "123 Main Street", "cityName": "Los Angeles", "countryCode": "US", - "countryName": "United States", "postalCode": "90001", "provinceCode": "CA" } From 2023f2ea8d7cc77d256ca20bb6436e632b6d5915 Mon Sep 17 00:00:00 2001 From: Ansh Dev Nagar Date: Thu, 5 Mar 2026 21:29:26 +0530 Subject: [PATCH 8/9] fix: mydhl bundle multi-piece shipment labels from per-package documents --- .../karrio/providers/mydhl/shipment/create.py | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/modules/connectors/mydhl/karrio/providers/mydhl/shipment/create.py b/modules/connectors/mydhl/karrio/providers/mydhl/shipment/create.py index e87838503a..1aa13b91d2 100644 --- a/modules/connectors/mydhl/karrio/providers/mydhl/shipment/create.py +++ b/modules/connectors/mydhl/karrio/providers/mydhl/shipment/create.py @@ -45,12 +45,30 @@ def _extract_details( ctx: dict = None, ) -> models.ShipmentDetails: tracking_number = str(shipment.shipmentTrackingNumber or "") + + # Collect labels from top-level documents and per-package documents + top_level_labels = [ + doc.content for doc in (shipment.documents or []) + if doc and doc.content + ] + package_labels = [ + doc.content + for pkg in (shipment.packages or []) + if pkg and pkg.documents + for doc in pkg.documents + if doc and doc.content + ] + labels = top_level_labels or package_labels label_doc = next( (doc for doc in (shipment.documents or []) if doc and doc.content), None, ) - label = label_doc.content if label_doc else "" label_format = label_doc.imageFormat if label_doc else "PDF" + label = lib.identity( + labels[0] if len(labels) == 1 + else lib.bundle_base64(labels, label_format) if len(labels) > 1 + else "" + ) package_tracking_numbers = [ pkg.trackingNumber for pkg in (shipment.packages or []) From 5ac9a64bbb6fa3e968d3c4a6deaf6b43e74fea31 Mon Sep 17 00:00:00 2001 From: Ansh Dev Nagar Date: Thu, 5 Mar 2026 23:45:15 +0530 Subject: [PATCH 9/9] fix: mydhl add missing product codes O and C to ShippingService enum --- modules/connectors/mydhl/karrio/providers/mydhl/units.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/connectors/mydhl/karrio/providers/mydhl/units.py b/modules/connectors/mydhl/karrio/providers/mydhl/units.py index d821a72343..bec6a3b412 100644 --- a/modules/connectors/mydhl/karrio/providers/mydhl/units.py +++ b/modules/connectors/mydhl/karrio/providers/mydhl/units.py @@ -63,7 +63,9 @@ class ShippingService(lib.StrEnum): # Domestic Express Services mydhl_express_domestic = "N" mydhl_express_domestic_12_00 = "1" + mydhl_express_domestic_10_30 = "O" mydhl_express_domestic_9_00 = "I" + mydhl_medical_express_domestic = "C" mydhl_same_day = "S" # Economy/Freight Services