feat(options): replace the tracked option with no tracking - #514
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the PDK’s shipment option model and related request/definition layers to replace the deprecated tracked option with its inverse noTracking, and introduces a centralized mechanism for sending API feature flags (notably x-dmp-no-tracking) on both SDK (generated) and legacy API requests to ensure the API contract returns the new option.
Changes:
- Replace the
trackedshipment option (and its settings keys) withnoTrackingacross option definitions, resources, settings views, and tests/snapshots. - Add
ApiFeatureFlags+ a new GuzzleFeatureFlagMiddlewareand wire it into the SDK client stack; add the same flags to legacyMyParcelApiServiceheaders. - Add a
$freshparameter toCarrierCapabilitiesRepository::getContractDefinitions()to force a cache rewrite when contract-definition shape changes.
Reviewed changes
Copilot reviewed 74 out of 74 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/Unit/Shipment/Model/Options/ShipmentOptionsTest.php | Updates unit tests to assert noTracking key/value preservation when mapping from capabilities. |
| tests/Unit/Shipment/Model/Options/DeliveryOptionsTest.php | Updates delivery options fixture data to use noTracking instead of tracked. |
| tests/Unit/SdkApi/Middleware/FeatureFlagMiddlewareTest.php | Adds unit tests ensuring SDK requests receive configured feature flag headers. |
| tests/Unit/Fulfilment/Model/ShipmentOptionsTest.php | Updates fulfilment shipment-options test input to noTracking. |
| tests/Unit/Context/Model/OrderDataContextTest.php | Updates order context fixtures to use noTracking tri-state values. |
| tests/Unit/Carrier/Repository/CarrierCapabilitiesRepositoryTest.php | Adds coverage for the new “fresh” refetch behavior + uses noTracking option in contract definitions. |
| tests/Unit/Base/Support/ApiFeatureFlagsTest.php | Adds unit tests for converting configured flags to request headers. |
| tests/Unit/App/Options/Definition/NoTrackingDefinitionTest.php | Adds unit tests for the new NoTrackingDefinition mapping/constraints. |
| tests/Unit/App/Endpoint/Resource/DeliveryOptionsV1ResourceTest.php | Replaces old tracked inversion tests with explicit noTracking tri-state formatting assertions. |
| tests/Unit/App/Action/Backend/Settings/UpdateProductSettingsActionTest.php | Updates product settings update test to use NoTrackingDefinition. |
| tests/Unit/App/Action/Backend/Account/UpdateAccountActionTest.php | Updates account update assertions from getTracked() to getNoTracking(). |
| tests/Unit/Api/Service/MyParcelApiServiceTest.php | Adds coverage for including configured feature flags in legacy API headers. |
| tests/SdkApi/Response/ExampleContractDefinitionsResponse.php | Removes deprecated tracked option from example contract definitions response. |
| tests/Bootstrap/MockCarrierCapabilitiesRepository.php | Updates mocked capability keys from tracked to noTracking. |
| tests/snapshots/UpdateShipmentsActionTest__it_updates_shipments__1.json | Snapshot update for noTracking tri-state serialization. |
| tests/snapshots/ShipmentTest__it_returns_empty_fulfilment_shipment_when_no_pdk_shipment_is_passed__1.json | Snapshot update replacing tracked with noTracking. |
| tests/snapshots/ShipmentTest__it_creates_fulfilment_shipment_from_pdk_shipment_with_data_set_shipment_with_all_options__1.json | Snapshot update replacing tracked with noTracking and option lists. |
| tests/snapshots/ShipmentTest__it_creates_fulfilment_shipment_from_pdk_shipment_with_data_set_empty_shipment__1.json | Snapshot update replacing tracked with noTracking. |
| tests/snapshots/SettingsViewTest__it_gets_settings_view_with_data_set_product_settings__1.json | Snapshot update renaming exportTracked to exportNoTracking and translation keys. |
| tests/snapshots/SettingsViewTest__it_gets_settings_view_with_data_set_carrier_settings__1.json | Snapshot update renaming exportTracked to exportNoTracking across carriers. |
| tests/snapshots/SaveOrderTest__it_creates_a_valid_order_collection_from_api_data_with_data_set_order_with_pickup__1.json | Snapshot update replacing tracked with noTracking in option lists. |
| tests/snapshots/SaveOrderTest__it_creates_a_valid_order_collection_from_api_data_with_data_set_order_containing_many_attributes__1.json | Snapshot update replacing tracked with noTracking in option lists. |
| tests/snapshots/QueryTest__it_creates_shipment_collection_from_queried_data_with_data_set_shipment_with_pickup__1.json | Snapshot update replacing tracked with noTracking in option lists + tri-state. |
| tests/snapshots/QueryTest__it_creates_shipment_collection_from_queried_data_with_data_set_shipment_with_drop-off_point__1.json | Snapshot update replacing tracked with noTracking. |
| tests/snapshots/QueryTest__it_creates_shipment_collection_from_queried_data_with_data_set_shipment_with_contract__1.json | Snapshot update replacing tracked with noTracking. |
| tests/snapshots/QueryTest__it_creates_shipment_collection_from_queried_data_with_data_set_normal_shipment__1.json | Snapshot update replacing tracked with noTracking. |
| tests/snapshots/QueryTest__it_creates_order_collection_from_queried_data__1.json | Snapshot update replacing tracked with noTracking in options. |
| tests/snapshots/PostOrdersTest__it_creates_a_valid_order_collection_from_api_data_with_data_set_one_order_with_pickup__1.json | Snapshot update replacing tracked with noTracking. |
| tests/snapshots/PostOrdersTest__it_creates_a_valid_order_collection_from_api_data_with_data_set_one_order_containing_many_attributes__1.json | Snapshot update replacing tracked with noTracking. |
| tests/snapshots/PdkOrderTest__it_creates_pdk_order_from_fulfilment_order_with_data_set_one_order_with_pickup__1.json | Snapshot update replacing tracked/exportTracked with noTracking/exportNoTracking. |
| tests/snapshots/PdkOrderTest__it_creates_pdk_order_from_fulfilment_order_with_data_set_one_order_containing_many_attributes__1.json | Snapshot update replacing tracked/exportTracked with noTracking/exportNoTracking. |
| tests/snapshots/PdkOrderTest__it_creates_a_storable_array_with_data_set_various_delivery_options__1.json | Snapshot update replacing tracked with noTracking. |
| tests/snapshots/PdkOrderTest__it_creates_a_storable_array_with_data_set_single_order__1.json | Snapshot update replacing tracked with noTracking. |
| tests/snapshots/PdkOrderTest__it_creates_a_storable_array_with_data_set_carrier_UPS_to_Netherlands_express__1.json | Snapshot update replacing tracked with noTracking. |
| tests/snapshots/PdkOrderTest__it_creates_a_storable_array_with_data_set_carrier_UPS_to_Belgium__1.json | Snapshot update replacing tracked with noTracking. |
| tests/snapshots/PdkOrderTest__it_creates_a_storable_array_with_data_set_carrier_GLS_with_saturday_delivery__1.json | Snapshot update replacing tracked with noTracking. |
| tests/snapshots/PdkOrderTest__it_creates_a_storable_array_with_data_set_carrier_GLS_with_insurance__1.json | Snapshot update replacing tracked with noTracking. |
| tests/snapshots/PdkOrderTest__it_creates_a_storable_array_with_data_set_carrier_GLS_to_Netherlands__1.json | Snapshot update replacing tracked with noTracking. |
| tests/snapshots/PdkOrderTest__it_creates_a_storable_array_with_data_set_carrier_GLS_to_Germany__1.json | Snapshot update replacing tracked with noTracking. |
| tests/snapshots/PdkOrderTest__it_creates_a_storable_array_with_data_set_carrier_GLS_custom_contract__1.json | Snapshot update replacing tracked with noTracking. |
| tests/snapshots/PdkOrderTest__it_creates_a_storable_array_with_data_set_carrier_dhl_for_you__1.json | Snapshot update replacing tracked with noTracking. |
| tests/snapshots/OrderTest__it_creates_fulfilment_order_from_pdk_order_with_data_set_order_without_shipments__1.json | Snapshot update replacing tracked with noTracking. |
| tests/snapshots/OrderTest__it_creates_fulfilment_order_from_pdk_order_with_data_set_order_with_shipments__1.json | Snapshot update replacing tracked with noTracking. |
| tests/snapshots/OrderTest__it_creates_fulfilment_order_from_pdk_order_with_data_set_empty_order__1.json | Snapshot update replacing tracked with noTracking. |
| tests/snapshots/FrontendRenderServiceTest__it_renders_component_with_data_set_product_settings__1.json | Snapshot update for exportNoTracking in rendered data. |
| tests/snapshots/FrontendRenderServiceTest__it_renders_component_with_data_set_plugin_settings__1.json | Snapshot update for exportNoTracking in rendered plugin settings. |
| tests/snapshots/FrontendRenderServiceTest__it_renders_component_with_data_set_order_list_column__1.json | Snapshot update replacing tracked with noTracking in rendered order list data. |
| tests/snapshots/FrontendRenderServiceTest__it_renders_component_with_data_set_order_box__1.json | Snapshot update replacing tracked with noTracking in rendered order box data. |
| tests/snapshots/FrontendRenderServiceTest__it_renders_component_with_data_set_init_script__1.json | Snapshot update for endpoint ordering + noTracking in initial data. |
| tests/snapshots/FrontendRenderServiceTest__it_renders_component_with_data_set_child_product_settings__1.json | Snapshot update for exportNoTracking in child product settings data. |
| tests/snapshots/ExportReturnActionTest__it_exports_return_with_data_set_simple_orders__1.json | Snapshot update replacing tracked/exportTracked with noTracking/exportNoTracking. |
| tests/snapshots/ExportReturnActionTest__it_exports_return_with_data_set_no_return_capabilities__1.json | Snapshot update replacing tracked/exportTracked with noTracking/exportNoTracking. |
| tests/snapshots/ExportReturnActionTest__it_exports_return_with_data_set_insurance__1.json | Snapshot update replacing tracked/exportTracked with noTracking/exportNoTracking. |
| tests/snapshots/CreateReturnShipmentsTest__it_creates_return_shipment_with_data_set_simple_domestic_shipment__1.json | Snapshot update replacing tracked with noTracking. |
| tests/snapshots/ContextServiceTest__it_gets_context_data_with_data_set_single_product__1.json | Snapshot update for exportNoTracking. |
| tests/snapshots/ContextServiceTest__it_gets_context_data_with_data_set_single_order__1.json | Snapshot update replacing tracked with noTracking in context payload. |
| tests/snapshots/ContextServiceTest__it_gets_context_data_with_data_set_multiple_products__1.json | Snapshot update for exportNoTracking. |
| tests/snapshots/ContextServiceTest__it_gets_context_data_with_data_set_multiple_orders__1.json | Snapshot update replacing tracked with noTracking in context payload. |
| tests/snapshots/AccountTest__it_creates_storable_array__1.json | Snapshot update replacing tracked with noTracking in stored account data. |
| tests/snapshots/AbstractSettingsRepositoryTest__it_retrieves_all_categories_and_fields__1.json | Snapshot update for exportNoTracking settings fields. |
| src/Settings/Model/ProductSettings.php | Updates product settings model docblock property to exportNoTracking. |
| src/Settings/Model/CarrierSettings.php | Updates carrier settings model docblock property to exportNoTracking. |
| src/SdkApi/Service/AbstractSdkApiService.php | Injects the feature flag middleware into the SDK Guzzle handler stack. |
| src/SdkApi/Middleware/FeatureFlagMiddleware.php | Adds a new SDK middleware to apply configured feature flags to outgoing requests. |
| src/Frontend/View/CarrierSettingsItemView.php | Removes carrier-specific tracked/mailbox settings logic from the UI layer. |
| src/Carrier/Repository/CarrierCapabilitiesRepository.php | Adds $fresh option to refetch and rewrite cached contract definitions. |
| src/Base/Support/ApiFeatureFlags.php | Introduces a central helper to convert configured flags to headers. |
| src/App/Options/Definition/TrackedDefinition.php | Removes the deprecated TrackedDefinition. |
| src/App/Options/Definition/NoTrackingDefinition.php | Adds NoTrackingDefinition mapping option keys to SDK contract keys. |
| src/App/Endpoint/Resource/DeliveryOptionsV1Resource.php | Changes formatting logic to emit noTracking opt-out per ADR-0013 and never send tracked. |
| src/Api/Service/MyParcelApiService.php | Adds configured feature flag headers to legacy API requests. |
| config/pdk-default.php | Adds apiFeatureFlags config default enabling x-dmp-no-tracking. |
| config/pdk-business-logic.php | Swaps option registry entry from TrackedDefinition to NoTrackingDefinition. |
| composer.json | Bumps myparcelnl/sdk requirement to ^11.0.0-beta.31@beta. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #514 +/- ##
============================================
+ Coverage 94.33% 94.36% +0.03%
- Complexity 2414 2428 +14
============================================
Files 352 355 +3
Lines 7726 7772 +46
============================================
+ Hits 7288 7334 +46
Misses 438 438 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
40a9701 to
82b86a2
Compare
036b588 to
df65079
Compare
df65079 to
a6aa8a9
Compare
* Guard carrier settings * test: clean carrier guard * fix: validate carrier entries * fix: ignore malformed carrier settings * refactor: simplify carrier settings guard
The MyParcel APIs expose feature flags as x-dmp-* headers. Which flags we send is now a single config entry, read by one support class and injected in both request layers: a Guzzle middleware for the generated SDK clients, and the header list of the legacy API service. Adding or removing a flag is a one-line config change. New settings/behaviour: the apiFeatureFlags config entry, shipping with x-dmp-no-tracking enabled, which makes the capabilities API return the noTracking option instead of the deprecated tracked one. Fixes INT-1694 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The API is retiring the tracked shipment option in favour of its inverse, no tracking. Tracking is the default wherever a carrier supports it, so the option now only expresses an explicit opt-out: it goes to the orders API as an empty object when a merchant switched it on, and is omitted otherwise. Swapping the entry in the order option definitions is what drives this: carrier settings, product settings, shipment options and both settings views all derive their keys from that registry. The option is offered per carrier and per product wherever capabilities allow it, and is no longer tied to holding a small package contract or to the international mailbox setting, which was carrier-specific reasoning the PDK should not carry. It still cannot be given a surcharge, and consumers still cannot choose it in the checkout. Requires SDK 11.0.0-beta.31, the first release carrying no_tracking on the shipment options model. Renames to pick up when upgrading, converted for merchants by the plugin migrations: - TrackedDefinition is removed, use NoTrackingDefinition - CarrierSettings::$exportTracked is now $exportNoTracking, with the inverse meaning - ProductSettings::$exportTracked is now $exportNoTracking, with the inverse meaning - ShipmentOptions::$tracked is now $noTracking, with the inverse meaning Fixes INT-1694 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contract definitions are cached per carrier, which is right for normal use but wrong during an upgrade that changes the shape of the response. Callers can now pass $fresh to call the API again and rewrite the cache, so a migration does not have to reach around the repository and delete its cache key. The parameter is named for what the caller wants rather than for how the cache behaves. Repository's own $force keeps its name, since renaming a public method's parameter would break anyone calling it with named arguments on PHP 8. Fixes INT-1694 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A migration that has to touch every order or product cannot run inline, because a large shop would time out. This service splits the work into chunks, hands each to the cron service as its own task, and staggers them so they do not all fire at once. Finding the records stays with the caller, since orders and products are queried in completely different ways per platform. Callers pass a fetcher that returns one page of ids at a time. The key the ids arrive under is configurable, so a caller can keep a key that already queued jobs rely on instead of stranding work scheduled before an upgrade. Extracted rather than copied: both plugins need this for the no tracking migration, and WooCommerce already had a private version of it on a version-based migration. Fixes INT-1694 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A page holding fewer records than the page size is the last one, so asking for another only costs a round trip. This matches the loop the WooCommerce version-based migration already used, which the service was extracted from. Fixes INT-1694 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The parameter existed so a refactored Migration6_5_1 could keep passing its own "orderIds" key. That migration has already run for merchants and is being left untouched, so nothing needs the parameter and every caller uses the default. The ids are now always passed under "ids". Fixes INT-1694 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
a6aa8a9 to
e188c27
Compare
Adds a case to FeatureFlagMiddlewareTest for a request that already sets a flag header itself. The request value wins, matching the legacy header merge in MyParcelApiService. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
replaces the deprecated tracked shipment option with its inverse, no tracking, and sends the
x-dmp-no-trackingfeature flag so the APIs stop returning the old option.Tracking is the default wherever a carrier supports it, so the option only ever expresses an explicit opt-out. How that reaches the API differs per endpoint: the Order v2 pull (delivery-options) endpoint gets
noTrackingas an ADR-0013 empty object, with no key at all when the merchant wants tracking, while the shipment and order v1 endpoints getno_trackingwith a truthy or falsy value. Merchants can set it per carrier and per product, wherever capabilities say the option exists. Verified against the acceptance API that sending the flag swapstrackedfornoTrackingin the contract definitions response, and that the two are never both present.Which feature flags we send is a single config entry, read by one support class and injected in both request layers: a Guzzle middleware for the generated SDK clients, and the header list of the legacy API service. Adding or retiring a flag is a one-line config change. What each flag does differs per flag — see the API feature flags overview.
Swapping the entry in the order option definitions is what drives the option change: carrier settings, product settings, shipment options and both settings views all derive their keys from that registry. The option is no longer tied to holding a small package contract or to the international mailbox setting, which was carrier-specific reasoning the PDK should not carry. It still cannot be given a surcharge, and consumers cannot choose it in the checkout.
getContractDefinitions()gained a$freshparameter so a caller can rewrite the cached copy rather than bypass it once. The plugin migrations need that: contract definitions stored before the flag was sent holdtrackedand nonoTracking, so they must be re-fetched.Requires SDK 11.0.0-beta.31, the first release carrying
no_trackingon the shipment options model.Renames to pick up when upgrading:
TrackedDefinitionis removed, useNoTrackingDefinitionCarrierSettings::$exportTrackedis now$exportNoTracking, with the inverse meaningProductSettings::$exportTrackedis now$exportNoTracking, with the inverse meaningShipmentOptions::$trackedis now$noTracking, with the inverse meaningThese are source-level renames. The only consumers are our own plugins, which are updated alongside this release, so it ships as a minor. Stored merchant values are converted by migrations in the plugin PRs that follow.
Translations for the new keys are in the PDK Vertalingen sheet. The generated files are gitignored, so none ship here.
Follow-ups: INT-1768 (OpenCart), INT-1769 (Shopify), INT-1289 (Magento).
Fixes INT-1694
🤖 Generated with Claude Code