diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index f9088459..2abdbb7c 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -1,4 +1,4 @@ -name: Validate and lint +name: Validate, lint, and test on: push: diff --git a/README.md b/README.md index d0839923..4d00757a 100644 --- a/README.md +++ b/README.md @@ -157,6 +157,7 @@ $connector->debugRequest( Then make requests with the connector as usual, and you'll hit the closure above every time a request is fired. You can also debug responses in a similar fashion – check out the [Saloon docs](https://docs.saloon.dev/digging-deeper/debugging#debugging-responses) for more details. +If you want to output your debug data to a file, you can do so with the `SellingPartnerApi::debugRequestToFile()`, `SellingPartnerApi::debugResponseToFile()`, and `SellingPartnerApi::debugToFile()` methods. These methods all take an `$outputPath` argument and an optional `$die` argument. ## Supported API segments diff --git a/resources/generator-config.json b/resources/generator-config.json index dedac60e..4a275b89 100644 --- a/resources/generator-config.json +++ b/resources/generator-config.json @@ -8,5 +8,6 @@ "baseFilesNamespace": "SellingPartnerApi", "namespaceSuffixes": { "resource": null - } + }, + "datetimeFormat": "Y-m-d\\TH:i:s\\Z" } diff --git a/resources/models/seller/catalog-items/v2022-04-01.json b/resources/models/seller/catalog-items/v2022-04-01.json index 567d45b5..39902a02 100644 --- a/resources/models/seller/catalog-items/v2022-04-01.json +++ b/resources/models/seller/catalog-items/v2022-04-01.json @@ -24,7 +24,7 @@ "tags": [ "CatalogItemsV20220401" ], - "description": "Search for and return a list of Amazon catalog items and associated information either by identifier or by keywords.\n\n**Usage Plans:**\n\n| Rate (requests per second) | Burst |\n| ---- | ---- |\n| 2 | 2 |\n\nThe `x-amzn-RateLimit-Limit` response header returns the usage plan rate limits that were applied to the requested operation, when available. The table above indicates the default rate and burst values for this operation. Selling partners whose business demands require higher throughput may observe higher rate and burst values than those shown here. For more information, refer to the [Usage Plans and Rate Limits in the Selling Partner API](doc:usage-plans-and-rate-limits-in-the-sp-api).", + "description": "Search for and return a list of Amazon catalog items and associated information either by identifier or by keywords.\n\n**Usage Plans:**\n\n| Rate (requests per second) | Burst |\n| ---- | ---- |\n| 5 | 5 |\n\nThe `x-amzn-RateLimit-Limit` response header returns the usage plan rate limits that were applied to the requested operation, when available. The table above indicates the default rate and burst values for this operation. Selling partners whose business demands require higher throughput may observe higher rate and burst values than those shown here. For more information, refer to the [Usage Plans and Rate Limits in the Selling Partner API](doc:usage-plans-and-rate-limits-in-the-sp-api).", "operationId": "searchCatalogItems", "parameters": [ { @@ -157,6 +157,7 @@ "type": "string", "enum": [ "attributes", + "classifications", "dimensions", "identifiers", "images", @@ -171,6 +172,10 @@ "value": "attributes", "description": "A JSON object containing structured item attribute data keyed by attribute name. Catalog item attributes conform to the related Amazon product type definitions available in the Selling Partner API for Product Type Definitions." }, + { + "value": "classifications", + "description": "Classifications (browse nodes) for an item in the Amazon catalog." + }, { "value": "dimensions", "description": "Dimensions for an item in the Amazon catalog." @@ -844,6 +849,29 @@ } ] }, + "classifications": [ + { + "marketplaceId": "ATVPDKIKX0DER", + "classifications": [ + { + "displayName": "QLED TVs", + "classificationId": "21489946011", + "parent": { + "displayName": "Televisions", + "classificationId": "172659", + "parent": { + "displayName": "Television & Video", + "classificationId": "1266092011", + "parent": { + "displayName": "Electronics", + "classificationId": "172282" + } + } + } + } + ] + } + ], "dimensions": [ { "marketplaceId": "ATVPDKIKX0DER", @@ -1188,6 +1216,7 @@ }, "includedData": { "value": [ + "classifications", "dimensions", "identifiers", "images", @@ -1224,6 +1253,29 @@ "items": [ { "asin": "B07N4M94X4", + "classifications": [ + { + "marketplaceId": "ATVPDKIKX0DER", + "classifications": [ + { + "displayName": "QLED TVs", + "classificationId": "21489946011", + "parent": { + "displayName": "Televisions", + "classificationId": "172659", + "parent": { + "displayName": "Television & Video", + "classificationId": "1266092011", + "parent": { + "displayName": "Electronics", + "classificationId": "172282" + } + } + } + } + ] + } + ], "dimensions": [ { "marketplaceId": "ATVPDKIKX0DER", @@ -1716,7 +1768,7 @@ "tags": [ "CatalogItemsV20220401" ], - "description": "Retrieves details for an item in the Amazon catalog.\n\n**Usage Plan:**\n\n| Rate (requests per second) | Burst |\n| ---- | ---- |\n| 2 | 2 |\n\nThe `x-amzn-RateLimit-Limit` response header returns the usage plan rate limits that were applied to the requested operation, when available. The table above indicates the default rate and burst values for this operation. Selling partners whose business demands require higher throughput may observe higher rate and burst values than those shown here. For more information, refer to the [Usage Plans and Rate Limits in the Selling Partner API](doc:usage-plans-and-rate-limits-in-the-sp-api).", + "description": "Retrieves details for an item in the Amazon catalog.\n\n**Usage Plan:**\n\n| Rate (requests per second) | Burst |\n| ---- | ---- |\n| 5 | 5 |\n\nThe `x-amzn-RateLimit-Limit` response header returns the usage plan rate limits that were applied to the requested operation, when available. The table above indicates the default rate and burst values for this operation. Selling partners whose business demands require higher throughput may observe higher rate and burst values than those shown here. For more information, refer to the [Usage Plans and Rate Limits in the Selling Partner API](doc:usage-plans-and-rate-limits-in-the-sp-api).", "operationId": "getCatalogItem", "parameters": [ { @@ -1755,6 +1807,7 @@ "type": "string", "enum": [ "attributes", + "classifications", "dimensions", "identifiers", "images", @@ -1769,6 +1822,10 @@ "value": "attributes", "description": "A JSON object containing structured item attribute data keyed by attribute name. Catalog item attributes conform to the related Amazon product type definitions available in the Selling Partner API for Product Type Definitions." }, + { + "value": "classifications", + "description": "Classifications (browse nodes) for an item in the Amazon catalog." + }, { "value": "dimensions", "description": "Dimensions for an item in the Amazon catalog." @@ -2340,6 +2397,29 @@ } ] }, + "classifications": [ + { + "marketplaceId": "ATVPDKIKX0DER", + "classifications": [ + { + "displayName": "QLED TVs", + "classificationId": "21489946011", + "parent": { + "displayName": "Televisions", + "classificationId": "172659", + "parent": { + "displayName": "Television & Video", + "classificationId": "1266092011", + "parent": { + "displayName": "Electronics", + "classificationId": "172282" + } + } + } + } + ] + } + ], "dimensions": [ { "marketplaceId": "ATVPDKIKX0DER", @@ -2679,6 +2759,7 @@ }, "includedData": { "value": [ + "classifications", "dimensions", "identifiers", "images", @@ -2693,6 +2774,29 @@ }, "response": { "asin": "B07N4M94X4", + "classifications": [ + { + "marketplaceId": "ATVPDKIKX0DER", + "classifications": [ + { + "displayName": "QLED TVs", + "classificationId": "21489946011", + "parent": { + "displayName": "Televisions", + "classificationId": "172659", + "parent": { + "displayName": "Television & Video", + "classificationId": "1266092011", + "parent": { + "displayName": "Electronics", + "classificationId": "172282" + } + } + } + } + ] + } + ], "dimensions": [ { "marketplaceId": "ATVPDKIKX0DER", @@ -3230,6 +3334,9 @@ "attributes": { "$ref": "#/components/schemas/ItemAttributes" }, + "classifications": { + "$ref": "#/components/schemas/ItemBrowseClassifications" + }, "dimensions": { "$ref": "#/components/schemas/ItemDimensions" }, @@ -3275,11 +3382,14 @@ "properties": { "displayName": { "type": "string", - "description": "Display name for the classification." + "description": "Display name for the classification (browse node)." }, "classificationId": { "type": "string", "description": "Identifier of the classification (browse node identifier)." + }, + "parent": { + "$ref": "#/components/schemas/ItemBrowseClassification" } }, "description": "Classification (browse node) associated with an Amazon catalog item." @@ -3318,6 +3428,33 @@ }, "description": "Role of an individual contributor in the creation of an item, such as author or actor." }, + "ItemBrowseClassifications": { + "type": "array", + "description": "Array of classifications (browse nodes) associated with the item in the Amazon catalog by Amazon marketplace.", + "items": { + "$ref": "#/components/schemas/ItemBrowseClassificationsByMarketplace" + } + }, + "ItemBrowseClassificationsByMarketplace": { + "required": [ + "marketplaceId" + ], + "type": "object", + "properties": { + "marketplaceId": { + "type": "string", + "description": "Amazon marketplace identifier." + }, + "classifications": { + "type": "array", + "description": "Classifications (browse nodes) associated with the item in the Amazon catalog for the indicated Amazon marketplace.", + "items": { + "$ref": "#/components/schemas/ItemBrowseClassification" + } + } + }, + "description": "Classifications (browse nodes) associated with the item in the Amazon catalog for the indicated Amazon marketplace." + }, "Dimension": { "type": "object", "properties": { diff --git a/src/Generator/Generators/RequestGenerator.php b/src/Generator/Generators/RequestGenerator.php index 851792f2..b15b4ccb 100644 --- a/src/Generator/Generators/RequestGenerator.php +++ b/src/Generator/Generators/RequestGenerator.php @@ -176,7 +176,7 @@ protected function generateRequestClass(Endpoint $endpoint): PhpFile if (SimpleType::isScalar($bodyType)) { $returnValText = '[$this->%s]'; } elseif ($bodyType === 'DateTime') { - $returnValText = '$this->%s->format(\DateTime::RFC3339)'; + $returnValText = '[$this->%s->format(\''.$this->config->datetimeFormat.'\')]'; } elseif (! Utils::isBuiltinType($bodyType)) { $returnValText = '$this->%s->toArray()'; } else { diff --git a/src/Seller/CatalogItemsV0/Dto/RelationshipType.php b/src/Seller/CatalogItemsV0/Dto/RelationshipType.php index 42c715aa..0edcbfd4 100644 --- a/src/Seller/CatalogItemsV0/Dto/RelationshipType.php +++ b/src/Seller/CatalogItemsV0/Dto/RelationshipType.php @@ -45,14 +45,14 @@ final class RelationshipType extends Dto * @param ?string $color The color variation of the item. * @param ?string $edition The edition variation of the item. * @param ?string $flavor The flavor variation of the item. - * @param ?string[] $gemType The gem type attributes of the item. + * @param ?string[] $gemType The gem type variations of the item. * @param ?string $golfClubFlex The golf club flex variation of an item. * @param ?string $handOrientation The hand orientation variation of an item. * @param ?string $hardwarePlatform The hardware platform variation of an item. - * @param ?string[] $materialType The material type attributes of the item. + * @param ?string[] $materialType The material type variations of an item. * @param ?string $metalType The metal type variation of an item. * @param ?string $model The model variation of an item. - * @param ?string[] $operatingSystem The operating system attributes of the item. + * @param ?string[] $operatingSystem The operating system variations of an item. * @param ?string $productTypeSubcategory The product type subcategory variation of an item. * @param ?string $ringSize The ring size variation of an item. * @param ?string $shaftMaterial The shaft material variation of an item. diff --git a/src/Seller/CatalogItemsV20220401/Dto/ItemBrowseClassification.php b/src/Seller/CatalogItemsV20220401/Dto/ItemBrowseClassification.php index 89d7fb97..cb479782 100644 --- a/src/Seller/CatalogItemsV20220401/Dto/ItemBrowseClassification.php +++ b/src/Seller/CatalogItemsV20220401/Dto/ItemBrowseClassification.php @@ -15,12 +15,14 @@ final class ItemBrowseClassification extends Dto { /** - * @param string $displayName Display name for the classification. + * @param string $displayName Display name for the classification (browse node). * @param string $classificationId Identifier of the classification (browse node identifier). + * @param ?ItemBrowseClassification $parent Classification (browse node) associated with an Amazon catalog item. */ public function __construct( public readonly string $displayName, public readonly string $classificationId, + public readonly ?ItemBrowseClassification $parent = null, ) { } } diff --git a/src/Seller/CatalogItemsV20220401/Dto/ItemBrowseClassificationsByMarketplace.php b/src/Seller/CatalogItemsV20220401/Dto/ItemBrowseClassificationsByMarketplace.php new file mode 100644 index 00000000..a786fd83 --- /dev/null +++ b/src/Seller/CatalogItemsV20220401/Dto/ItemBrowseClassificationsByMarketplace.php @@ -0,0 +1,28 @@ + [ItemBrowseClassification::class]]; + + /** + * @param string $marketplaceId Amazon marketplace identifier. + * @param ItemBrowseClassification[]|null $classifications Classifications (browse nodes) associated with the item in the Amazon catalog for the indicated Amazon marketplace. + */ + public function __construct( + public readonly string $marketplaceId, + public readonly ?array $classifications = null, + ) { + } +} diff --git a/src/Seller/CatalogItemsV20220401/Responses/Item.php b/src/Seller/CatalogItemsV20220401/Responses/Item.php index 143efc0c..cf562eb5 100644 --- a/src/Seller/CatalogItemsV20220401/Responses/Item.php +++ b/src/Seller/CatalogItemsV20220401/Responses/Item.php @@ -11,6 +11,7 @@ namespace SellingPartnerApi\Seller\CatalogItemsV20220401\Responses; use SellingPartnerApi\Response; +use SellingPartnerApi\Seller\CatalogItemsV20220401\Dto\ItemBrowseClassificationsByMarketplace; use SellingPartnerApi\Seller\CatalogItemsV20220401\Dto\ItemDimensionsByMarketplace; use SellingPartnerApi\Seller\CatalogItemsV20220401\Dto\ItemIdentifiersByMarketplace; use SellingPartnerApi\Seller\CatalogItemsV20220401\Dto\ItemImagesByMarketplace; @@ -23,6 +24,7 @@ final class Item extends Response { protected static array $complexArrayTypes = [ + 'classifications' => [ItemBrowseClassificationsByMarketplace::class], 'dimensions' => [ItemDimensionsByMarketplace::class], 'identifiers' => [ItemIdentifiersByMarketplace::class], 'images' => [ItemImagesByMarketplace::class], @@ -36,6 +38,7 @@ final class Item extends Response /** * @param string $asin Amazon Standard Identification Number (ASIN) is the unique identifier for an item in the Amazon catalog. * @param ?mixed[] $attributes A JSON object that contains structured item attribute data keyed by attribute name. Catalog item attributes conform to the related product type definitions available in the Selling Partner API for Product Type Definitions. + * @param ItemBrowseClassificationsByMarketplace[]|null $classifications Array of classifications (browse nodes) associated with the item in the Amazon catalog by Amazon marketplace. * @param ItemDimensionsByMarketplace[]|null $dimensions Array of dimensions associated with the item in the Amazon catalog by Amazon marketplace. * @param ItemIdentifiersByMarketplace[]|null $identifiers Identifiers associated with the item in the Amazon catalog, such as UPC and EAN identifiers. * @param ItemImagesByMarketplace[]|null $images Images for an item in the Amazon catalog. @@ -48,6 +51,7 @@ final class Item extends Response public function __construct( public readonly string $asin, public readonly ?array $attributes = null, + public readonly ?array $classifications = null, public readonly ?array $dimensions = null, public readonly ?array $identifiers = null, public readonly ?array $images = null, diff --git a/src/Seller/DataKioskV20231115/Dto/Pagination2.php b/src/Seller/DataKioskV20231115/Dto/Pagination2.php new file mode 100644 index 00000000..208bcebe --- /dev/null +++ b/src/Seller/DataKioskV20231115/Dto/Pagination2.php @@ -0,0 +1,24 @@ + $this->processingStatuses, 'pageSize' => $this->pageSize, - 'createdSince' => $this->createdSince?->format(\DateTime::RFC3339), - 'createdUntil' => $this->createdUntil?->format(\DateTime::RFC3339), + 'createdSince' => $this->createdSince?->format('Y-m-d\TH:i:s\Z'), + 'createdUntil' => $this->createdUntil?->format('Y-m-d\TH:i:s\Z'), 'paginationToken' => $this->paginationToken, ]); } diff --git a/src/Seller/DataKioskV20231115/Responses/GetQueriesResponse.php b/src/Seller/DataKioskV20231115/Responses/GetQueriesResponse.php index 61f2bfde..f84b4c8e 100644 --- a/src/Seller/DataKioskV20231115/Responses/GetQueriesResponse.php +++ b/src/Seller/DataKioskV20231115/Responses/GetQueriesResponse.php @@ -11,7 +11,7 @@ namespace SellingPartnerApi\Seller\DataKioskV20231115\Responses; use SellingPartnerApi\Response; -use SellingPartnerApi\Seller\DataKioskV20231115\Dto\Pagination; +use SellingPartnerApi\Seller\DataKioskV20231115\Dto\Pagination2; final class GetQueriesResponse extends Response { @@ -19,11 +19,11 @@ final class GetQueriesResponse extends Response /** * @param Query[] $queries A list of queries. - * @param ?Pagination $pagination When a query produces results that are not included in the data document, pagination occurs. This means the results are divided into pages. To retrieve the next page, you must pass a `CreateQuerySpecification` object with `paginationToken` set to this object's `nextToken` and with `query` set to this object's `query` in the subsequent `createQuery` request. When there are no more pages to fetch, the `nextToken` field will be absent. + * @param ?Pagination2 $pagination When a request has results that are not included in this response, pagination occurs. This means the results are divided into pages. To retrieve the next page, you must pass the `nextToken` as the `paginationToken` query parameter in the subsequent `getQueries` request. All other parameters must be provided with the same values that were provided with the request that generated this token, with the exception of `pageSize` which can be modified between calls to `getQueries`. When there are no more pages to fetch, the `nextToken` field will be absent. */ public function __construct( public readonly array $queries, - public readonly ?Pagination $pagination = null, + public readonly ?Pagination2 $pagination = null, ) { } } diff --git a/src/Seller/FBAInboundV0/Requests/ConfirmPreorder.php b/src/Seller/FBAInboundV0/Requests/ConfirmPreorder.php index c9bf4296..b8e151c4 100644 --- a/src/Seller/FBAInboundV0/Requests/ConfirmPreorder.php +++ b/src/Seller/FBAInboundV0/Requests/ConfirmPreorder.php @@ -37,7 +37,7 @@ public function __construct( public function defaultQuery(): array { - return array_filter(['NeedByDate' => $this->needByDate?->format(\DateTime::RFC3339), 'MarketplaceId' => $this->marketplaceId]); + return array_filter(['NeedByDate' => $this->needByDate?->format('Y-m-d\TH:i:s\Z'), 'MarketplaceId' => $this->marketplaceId]); } public function resolveEndpoint(): string diff --git a/src/Seller/FBAInboundV0/Requests/GetShipmentItems.php b/src/Seller/FBAInboundV0/Requests/GetShipmentItems.php index c7982c05..c4d0d3ca 100644 --- a/src/Seller/FBAInboundV0/Requests/GetShipmentItems.php +++ b/src/Seller/FBAInboundV0/Requests/GetShipmentItems.php @@ -44,8 +44,8 @@ public function defaultQuery(): array return array_filter([ 'QueryType' => $this->queryType, 'MarketplaceId' => $this->marketplaceId, - 'LastUpdatedAfter' => $this->lastUpdatedAfter?->format(\DateTime::RFC3339), - 'LastUpdatedBefore' => $this->lastUpdatedBefore?->format(\DateTime::RFC3339), + 'LastUpdatedAfter' => $this->lastUpdatedAfter?->format('Y-m-d\TH:i:s\Z'), + 'LastUpdatedBefore' => $this->lastUpdatedBefore?->format('Y-m-d\TH:i:s\Z'), 'NextToken' => $this->nextToken, ]); } diff --git a/src/Seller/FBAInboundV0/Requests/GetShipments.php b/src/Seller/FBAInboundV0/Requests/GetShipments.php index 66c08ba3..a89bef79 100644 --- a/src/Seller/FBAInboundV0/Requests/GetShipments.php +++ b/src/Seller/FBAInboundV0/Requests/GetShipments.php @@ -50,8 +50,8 @@ public function defaultQuery(): array 'MarketplaceId' => $this->marketplaceId, 'ShipmentStatusList' => $this->shipmentStatusList, 'ShipmentIdList' => $this->shipmentIdList, - 'LastUpdatedAfter' => $this->lastUpdatedAfter?->format(\DateTime::RFC3339), - 'LastUpdatedBefore' => $this->lastUpdatedBefore?->format(\DateTime::RFC3339), + 'LastUpdatedAfter' => $this->lastUpdatedAfter?->format('Y-m-d\TH:i:s\Z'), + 'LastUpdatedBefore' => $this->lastUpdatedBefore?->format('Y-m-d\TH:i:s\Z'), 'NextToken' => $this->nextToken, ]); } diff --git a/src/Seller/FBAInventoryV1/Requests/GetInventorySummaries.php b/src/Seller/FBAInventoryV1/Requests/GetInventorySummaries.php index 90ce38fb..be755efc 100644 --- a/src/Seller/FBAInventoryV1/Requests/GetInventorySummaries.php +++ b/src/Seller/FBAInventoryV1/Requests/GetInventorySummaries.php @@ -52,7 +52,7 @@ public function defaultQuery(): array 'granularityId' => $this->granularityId, 'marketplaceIds' => $this->marketplaceIds, 'details' => $this->details, - 'startDateTime' => $this->startDateTime?->format(\DateTime::RFC3339), + 'startDateTime' => $this->startDateTime?->format('Y-m-d\TH:i:s\Z'), 'sellerSkus' => $this->sellerSkus, 'sellerSku' => $this->sellerSku, 'nextToken' => $this->nextToken, diff --git a/src/Seller/FBAOutboundV20200701/Requests/ListAllFulfillmentOrders.php b/src/Seller/FBAOutboundV20200701/Requests/ListAllFulfillmentOrders.php index 7956de71..f242bf4f 100644 --- a/src/Seller/FBAOutboundV20200701/Requests/ListAllFulfillmentOrders.php +++ b/src/Seller/FBAOutboundV20200701/Requests/ListAllFulfillmentOrders.php @@ -35,7 +35,7 @@ public function __construct( public function defaultQuery(): array { - return array_filter(['queryStartDate' => $this->queryStartDate?->format(\DateTime::RFC3339), 'nextToken' => $this->nextToken]); + return array_filter(['queryStartDate' => $this->queryStartDate?->format('Y-m-d\TH:i:s\Z'), 'nextToken' => $this->nextToken]); } public function resolveEndpoint(): string diff --git a/src/Seller/FeedsV20210630/Requests/GetFeeds.php b/src/Seller/FeedsV20210630/Requests/GetFeeds.php index 8dc27955..b77370a6 100644 --- a/src/Seller/FeedsV20210630/Requests/GetFeeds.php +++ b/src/Seller/FeedsV20210630/Requests/GetFeeds.php @@ -51,8 +51,8 @@ public function defaultQuery(): array 'marketplaceIds' => $this->marketplaceIds, 'pageSize' => $this->pageSize, 'processingStatuses' => $this->processingStatuses, - 'createdSince' => $this->createdSince?->format(\DateTime::RFC3339), - 'createdUntil' => $this->createdUntil?->format(\DateTime::RFC3339), + 'createdSince' => $this->createdSince?->format('Y-m-d\TH:i:s\Z'), + 'createdUntil' => $this->createdUntil?->format('Y-m-d\TH:i:s\Z'), 'nextToken' => $this->nextToken, ]); } diff --git a/src/Seller/FinancesV0/Requests/ListFinancialEventGroups.php b/src/Seller/FinancesV0/Requests/ListFinancialEventGroups.php index 3207051d..de60fb96 100644 --- a/src/Seller/FinancesV0/Requests/ListFinancialEventGroups.php +++ b/src/Seller/FinancesV0/Requests/ListFinancialEventGroups.php @@ -41,8 +41,8 @@ public function defaultQuery(): array { return array_filter([ 'MaxResultsPerPage' => $this->maxResultsPerPage, - 'FinancialEventGroupStartedBefore' => $this->financialEventGroupStartedBefore?->format(\DateTime::RFC3339), - 'FinancialEventGroupStartedAfter' => $this->financialEventGroupStartedAfter?->format(\DateTime::RFC3339), + 'FinancialEventGroupStartedBefore' => $this->financialEventGroupStartedBefore?->format('Y-m-d\TH:i:s\Z'), + 'FinancialEventGroupStartedAfter' => $this->financialEventGroupStartedAfter?->format('Y-m-d\TH:i:s\Z'), 'NextToken' => $this->nextToken, ]); } diff --git a/src/Seller/FinancesV0/Requests/ListFinancialEvents.php b/src/Seller/FinancesV0/Requests/ListFinancialEvents.php index 967f1729..e981cb2a 100644 --- a/src/Seller/FinancesV0/Requests/ListFinancialEvents.php +++ b/src/Seller/FinancesV0/Requests/ListFinancialEvents.php @@ -41,8 +41,8 @@ public function defaultQuery(): array { return array_filter([ 'MaxResultsPerPage' => $this->maxResultsPerPage, - 'PostedAfter' => $this->postedAfter?->format(\DateTime::RFC3339), - 'PostedBefore' => $this->postedBefore?->format(\DateTime::RFC3339), + 'PostedAfter' => $this->postedAfter?->format('Y-m-d\TH:i:s\Z'), + 'PostedBefore' => $this->postedBefore?->format('Y-m-d\TH:i:s\Z'), 'NextToken' => $this->nextToken, ]); } diff --git a/src/Seller/FinancesV0/Requests/ListFinancialEventsByGroupId.php b/src/Seller/FinancesV0/Requests/ListFinancialEventsByGroupId.php index ab85f8d7..77db6259 100644 --- a/src/Seller/FinancesV0/Requests/ListFinancialEventsByGroupId.php +++ b/src/Seller/FinancesV0/Requests/ListFinancialEventsByGroupId.php @@ -43,8 +43,8 @@ public function defaultQuery(): array { return array_filter([ 'MaxResultsPerPage' => $this->maxResultsPerPage, - 'PostedAfter' => $this->postedAfter?->format(\DateTime::RFC3339), - 'PostedBefore' => $this->postedBefore?->format(\DateTime::RFC3339), + 'PostedAfter' => $this->postedAfter?->format('Y-m-d\TH:i:s\Z'), + 'PostedBefore' => $this->postedBefore?->format('Y-m-d\TH:i:s\Z'), 'NextToken' => $this->nextToken, ]); } diff --git a/src/Seller/MessagingV1/Dto/Embedded.php b/src/Seller/MessagingV1/Dto/Embedded.php index f6be44b6..2ad7005e 100644 --- a/src/Seller/MessagingV1/Dto/Embedded.php +++ b/src/Seller/MessagingV1/Dto/Embedded.php @@ -14,10 +14,10 @@ final class Embedded extends Dto { - protected static array $complexArrayTypes = ['actions' => [LinkObject::class]]; + protected static array $complexArrayTypes = ['actions' => [GetMessagingActionResponse::class]]; /** - * @param LinkObject[] $actions Eligible actions for the specified amazonOrderId. + * @param GetMessagingActionResponse[] $actions */ public function __construct( public readonly array $actions, diff --git a/src/Seller/MessagingV1/Dto/Embedded2.php b/src/Seller/MessagingV1/Dto/Embedded2.php new file mode 100644 index 00000000..da54bace --- /dev/null +++ b/src/Seller/MessagingV1/Dto/Embedded2.php @@ -0,0 +1,24 @@ + [Error::class]]; /** - * @param ?Links $links - * @param ?Embedded $embedded + * @param ?Links2 $links + * @param ?Embedded2 $embedded * @param ?MessagingAction $payload A simple object containing the name of the template. * @param Error[]|null $errors A list of error responses returned when a request is unsuccessful. */ public function __construct( - public readonly ?Links $links = null, - public readonly ?Embedded $embedded = null, + public readonly ?Links2 $links = null, + public readonly ?Embedded2 $embedded = null, public readonly ?MessagingAction $payload = null, public readonly ?array $errors = null, ) { diff --git a/src/Seller/MessagingV1/Dto/GetSchemaResponse.php b/src/Seller/MessagingV1/Dto/GetSchemaResponse.php index b5ee5419..50d57138 100644 --- a/src/Seller/MessagingV1/Dto/GetSchemaResponse.php +++ b/src/Seller/MessagingV1/Dto/GetSchemaResponse.php @@ -19,12 +19,12 @@ final class GetSchemaResponse extends Dto protected static array $complexArrayTypes = ['errors' => [Error::class]]; /** - * @param ?Links $links + * @param ?Links3 $links * @param ?array[] $payload A JSON schema document describing the expected payload of the action. This object can be validated against http://json-schema.org/draft-04/schema. * @param Error[]|null $errors A list of error responses returned when a request is unsuccessful. */ public function __construct( - public readonly ?Links $links = null, + public readonly ?Links3 $links = null, public readonly ?array $payload = null, public readonly ?array $errors = null, ) { diff --git a/src/Seller/MessagingV1/Dto/Links2.php b/src/Seller/MessagingV1/Dto/Links2.php new file mode 100644 index 00000000..44aaa391 --- /dev/null +++ b/src/Seller/MessagingV1/Dto/Links2.php @@ -0,0 +1,26 @@ + $this->processingStatuses, 'marketplaceIds' => $this->marketplaceIds, 'pageSize' => $this->pageSize, - 'createdSince' => $this->createdSince?->format(\DateTime::RFC3339), - 'createdUntil' => $this->createdUntil?->format(\DateTime::RFC3339), + 'createdSince' => $this->createdSince?->format('Y-m-d\TH:i:s\Z'), + 'createdUntil' => $this->createdUntil?->format('Y-m-d\TH:i:s\Z'), 'nextToken' => $this->nextToken, ]); } diff --git a/src/Seller/SolicitationsV1/Dto/Embedded.php b/src/Seller/SolicitationsV1/Dto/Embedded.php index 045be9fe..c4819844 100644 --- a/src/Seller/SolicitationsV1/Dto/Embedded.php +++ b/src/Seller/SolicitationsV1/Dto/Embedded.php @@ -14,10 +14,10 @@ final class Embedded extends Dto { - protected static array $complexArrayTypes = ['actions' => [LinkObject::class]]; + protected static array $complexArrayTypes = ['actions' => [GetSolicitationActionResponse::class]]; /** - * @param LinkObject[] $actions Eligible actions for the specified amazonOrderId. + * @param GetSolicitationActionResponse[] $actions */ public function __construct( public readonly array $actions, diff --git a/src/Seller/SolicitationsV1/Dto/Embedded2.php b/src/Seller/SolicitationsV1/Dto/Embedded2.php new file mode 100644 index 00000000..d02eba1c --- /dev/null +++ b/src/Seller/SolicitationsV1/Dto/Embedded2.php @@ -0,0 +1,24 @@ + [Error::class]]; /** - * @param ?Links $links + * @param ?Links3 $links * @param ?array[] $payload A JSON schema document describing the expected payload of the action. This object can be validated against http://json-schema.org/draft-04/schema. * @param Error[]|null $errors A list of error responses returned when a request is unsuccessful. */ public function __construct( - public readonly ?Links $links = null, + public readonly ?Links3 $links = null, public readonly ?array $payload = null, public readonly ?array $errors = null, ) { diff --git a/src/Seller/SolicitationsV1/Dto/GetSolicitationActionResponse.php b/src/Seller/SolicitationsV1/Dto/GetSolicitationActionResponse.php index fafafbb1..b2728a5a 100644 --- a/src/Seller/SolicitationsV1/Dto/GetSolicitationActionResponse.php +++ b/src/Seller/SolicitationsV1/Dto/GetSolicitationActionResponse.php @@ -19,14 +19,14 @@ final class GetSolicitationActionResponse extends Dto protected static array $complexArrayTypes = ['errors' => [Error::class]]; /** - * @param ?Links $links - * @param ?Embedded $embedded + * @param ?Links2 $links + * @param ?Embedded2 $embedded * @param ?SolicitationsAction $payload A simple object containing the name of the template. * @param Error[]|null $errors A list of error responses returned when a request is unsuccessful. */ public function __construct( - public readonly ?Links $links = null, - public readonly ?Embedded $embedded = null, + public readonly ?Links2 $links = null, + public readonly ?Embedded2 $embedded = null, public readonly ?SolicitationsAction $payload = null, public readonly ?array $errors = null, ) { diff --git a/src/Seller/SolicitationsV1/Dto/Links2.php b/src/Seller/SolicitationsV1/Dto/Links2.php new file mode 100644 index 00000000..ebd4a9d4 --- /dev/null +++ b/src/Seller/SolicitationsV1/Dto/Links2.php @@ -0,0 +1,26 @@ +debugRequest( + function (PendingRequest $pendingRequest, RequestInterface $psrRequest) use ($outputPath) { + $headers = []; + foreach ($psrRequest->getHeaders() as $headerName => $value) { + $headers[$headerName] = implode(';', $value); + } + + $className = explode('\\', $pendingRequest->getRequest()::class); + $label = end($className); + + VarDumper::setHandler(function ($var) use ($outputPath, $label) { + $file = fopen($outputPath, 'a'); + + $cloner = new VarCloner(); + $dumper = new CliDumper($file); + $cloned = $cloner->cloneVar($var) + ->withContext(['label' => 'Saloon Request('.$label.') ->']); + $dumper->dump($cloned); + + fclose($file); + }); + VarDumper::dump([ + 'connector' => $pendingRequest->getConnector()::class, + 'request' => $pendingRequest->getRequest()::class, + 'method' => $psrRequest->getMethod(), + 'uri' => (string) $psrRequest->getUri(), + 'headers' => $headers, + 'body' => (string) $psrRequest->getBody(), + ]); + }, + die: $die, + ); + } + + /** + * I couldn't find any great way of reusing the original Debugger::symfonyResponseDebugger() method from + * the Saloon package, so I'm just going to copy and paste the code here, but with the VarDumper + * configured to dump to a file. + */ + public function debugResponseToFile(string $outputPath, bool $die = false): static + { + return $this->debugResponse( + function (Response $response, ResponseInterface $psrResponse) use ($outputPath) { + $headers = []; + foreach ($psrResponse->getHeaders() as $headerName => $value) { + $headers[$headerName] = implode(';', $value); + } + + $className = explode('\\', $response->getRequest()::class); + $label = end($className); + + VarDumper::setHandler(function ($var) use ($outputPath, $label) { + $file = fopen($outputPath, 'a'); + + $cloner = new VarCloner(); + $dumper = new CliDumper($file); + $cloned = $cloner->cloneVar($var) + ->withContext(['label' => 'Saloon Response('.$label.') ->']); + $dumper->dump($cloned); + + fclose($file); + }); + VarDumper::dump([ + 'status' => $response->status(), + 'headers' => $headers, + 'body' => $response->body(), + ]); + }, + die: $die, + ); + } + + public function debugToFile(string $outputPath, bool $die = false): static + { + return $this->debugRequestToFile($outputPath)->debugResponseToFile($outputPath, $die); + } + public function getAccessToken( array $scopes = [], string $scopeSeparator = ' ', diff --git a/src/Traits/Deserializes.php b/src/Traits/Deserializes.php index 9f4f1c63..7d80af9e 100644 --- a/src/Traits/Deserializes.php +++ b/src/Traits/Deserializes.php @@ -12,6 +12,8 @@ trait Deserializes { use HasComplexArrayTypes; + protected static string $datetimeFormat = 'Y-m-d\TH:i:s\Z'; + public static function deserialize(mixed $data): mixed { if (is_null($data)) { @@ -69,7 +71,7 @@ protected static function deserializeValue(mixed $value, array|string $type): mi 'float' => (float) $value, 'bool' => (bool) $value, 'string' => (string) $value, - 'date', 'datetime' => DateTime::createFromFormat(DateTime::RFC3339, $value), + 'date', 'datetime' => DateTime::createFromFormat(static::$datetimeFormat, $value), 'array', 'mixed' => $value, 'null' => null, default => chr(0), @@ -85,7 +87,7 @@ protected static function deserializeValue(mixed $value, array|string $type): mi if (strlen($value) === 10) { return DateTime::createFromFormat('Y-m-d', $value); } else { - return DateTime::createFromFormat('Y-m-d\TH:i:sZ', $value); + return DateTime::createFromFormat(static::$datetimeFormat, $value); } } diff --git a/src/Traits/HasArrayableAttributes.php b/src/Traits/HasArrayableAttributes.php index 2bcb7879..41dbcc0c 100644 --- a/src/Traits/HasArrayableAttributes.php +++ b/src/Traits/HasArrayableAttributes.php @@ -4,7 +4,6 @@ namespace SellingPartnerApi\Traits; -use DateTime; use DateTimeInterface; use ReflectionClass; use SellingPartnerApi\Exceptions\InvalidAttributeTypeException; @@ -13,6 +12,8 @@ trait HasArrayableAttributes { use HasComplexArrayTypes; + protected static string $datetimeFormat = 'Y-m-d\TH:i:s\Z'; + /** * @var array{string, string} * @@ -61,7 +62,7 @@ public function valueToArray(mixed $value, array|string $type): mixed if (is_null($value)) { return null; } elseif ($value instanceof DateTimeInterface) { - return $value->format(DateTime::RFC3339); + return $value->format(static::$datetimeFormat); } elseif (is_string($type)) { if (class_exists($type)) { return $value->toArray(); diff --git a/src/Vendor/DirectFulfillmentOrdersV1/Requests/GetOrders.php b/src/Vendor/DirectFulfillmentOrdersV1/Requests/GetOrders.php index 091e8dac..16a8924d 100644 --- a/src/Vendor/DirectFulfillmentOrdersV1/Requests/GetOrders.php +++ b/src/Vendor/DirectFulfillmentOrdersV1/Requests/GetOrders.php @@ -51,8 +51,8 @@ public function __construct( public function defaultQuery(): array { return array_filter([ - 'createdAfter' => $this->createdAfter?->format(\DateTime::RFC3339), - 'createdBefore' => $this->createdBefore?->format(\DateTime::RFC3339), + 'createdAfter' => $this->createdAfter?->format('Y-m-d\TH:i:s\Z'), + 'createdBefore' => $this->createdBefore?->format('Y-m-d\TH:i:s\Z'), 'shipFromPartyId' => $this->shipFromPartyId, 'status' => $this->status, 'limit' => $this->limit, diff --git a/src/Vendor/DirectFulfillmentOrdersV20211228/Requests/GetOrders.php b/src/Vendor/DirectFulfillmentOrdersV20211228/Requests/GetOrders.php index 77dba1cf..ac8ec107 100644 --- a/src/Vendor/DirectFulfillmentOrdersV20211228/Requests/GetOrders.php +++ b/src/Vendor/DirectFulfillmentOrdersV20211228/Requests/GetOrders.php @@ -52,8 +52,8 @@ public function __construct( public function defaultQuery(): array { return array_filter([ - 'createdAfter' => $this->createdAfter?->format(\DateTime::RFC3339), - 'createdBefore' => $this->createdBefore?->format(\DateTime::RFC3339), + 'createdAfter' => $this->createdAfter?->format('Y-m-d\TH:i:s\Z'), + 'createdBefore' => $this->createdBefore?->format('Y-m-d\TH:i:s\Z'), 'shipFromPartyId' => $this->shipFromPartyId, 'status' => $this->status, 'limit' => $this->limit, diff --git a/src/Vendor/DirectFulfillmentShippingV1/Requests/GetCustomerInvoices.php b/src/Vendor/DirectFulfillmentShippingV1/Requests/GetCustomerInvoices.php index 7a879332..cfd9bd56 100644 --- a/src/Vendor/DirectFulfillmentShippingV1/Requests/GetCustomerInvoices.php +++ b/src/Vendor/DirectFulfillmentShippingV1/Requests/GetCustomerInvoices.php @@ -48,8 +48,8 @@ public function __construct( public function defaultQuery(): array { return array_filter([ - 'createdAfter' => $this->createdAfter?->format(\DateTime::RFC3339), - 'createdBefore' => $this->createdBefore?->format(\DateTime::RFC3339), + 'createdAfter' => $this->createdAfter?->format('Y-m-d\TH:i:s\Z'), + 'createdBefore' => $this->createdBefore?->format('Y-m-d\TH:i:s\Z'), 'shipFromPartyId' => $this->shipFromPartyId, 'limit' => $this->limit, 'sortOrder' => $this->sortOrder, diff --git a/src/Vendor/DirectFulfillmentShippingV1/Requests/GetPackingSlips.php b/src/Vendor/DirectFulfillmentShippingV1/Requests/GetPackingSlips.php index 751f8bc1..350b178d 100644 --- a/src/Vendor/DirectFulfillmentShippingV1/Requests/GetPackingSlips.php +++ b/src/Vendor/DirectFulfillmentShippingV1/Requests/GetPackingSlips.php @@ -47,8 +47,8 @@ public function __construct( public function defaultQuery(): array { return array_filter([ - 'createdAfter' => $this->createdAfter?->format(\DateTime::RFC3339), - 'createdBefore' => $this->createdBefore?->format(\DateTime::RFC3339), + 'createdAfter' => $this->createdAfter?->format('Y-m-d\TH:i:s\Z'), + 'createdBefore' => $this->createdBefore?->format('Y-m-d\TH:i:s\Z'), 'shipFromPartyId' => $this->shipFromPartyId, 'limit' => $this->limit, 'sortOrder' => $this->sortOrder, diff --git a/src/Vendor/DirectFulfillmentShippingV1/Requests/GetShippingLabels.php b/src/Vendor/DirectFulfillmentShippingV1/Requests/GetShippingLabels.php index 5d6da398..f9419f22 100644 --- a/src/Vendor/DirectFulfillmentShippingV1/Requests/GetShippingLabels.php +++ b/src/Vendor/DirectFulfillmentShippingV1/Requests/GetShippingLabels.php @@ -44,8 +44,8 @@ public function __construct( public function defaultQuery(): array { return array_filter([ - 'createdAfter' => $this->createdAfter?->format(\DateTime::RFC3339), - 'createdBefore' => $this->createdBefore?->format(\DateTime::RFC3339), + 'createdAfter' => $this->createdAfter?->format('Y-m-d\TH:i:s\Z'), + 'createdBefore' => $this->createdBefore?->format('Y-m-d\TH:i:s\Z'), 'shipFromPartyId' => $this->shipFromPartyId, 'limit' => $this->limit, 'sortOrder' => $this->sortOrder, diff --git a/src/Vendor/DirectFulfillmentShippingV20211228/Requests/GetCustomerInvoices.php b/src/Vendor/DirectFulfillmentShippingV20211228/Requests/GetCustomerInvoices.php index 3d4b4de4..fb3c7dfd 100644 --- a/src/Vendor/DirectFulfillmentShippingV20211228/Requests/GetCustomerInvoices.php +++ b/src/Vendor/DirectFulfillmentShippingV20211228/Requests/GetCustomerInvoices.php @@ -48,8 +48,8 @@ public function __construct( public function defaultQuery(): array { return array_filter([ - 'createdAfter' => $this->createdAfter?->format(\DateTime::RFC3339), - 'createdBefore' => $this->createdBefore?->format(\DateTime::RFC3339), + 'createdAfter' => $this->createdAfter?->format('Y-m-d\TH:i:s\Z'), + 'createdBefore' => $this->createdBefore?->format('Y-m-d\TH:i:s\Z'), 'shipFromPartyId' => $this->shipFromPartyId, 'limit' => $this->limit, 'sortOrder' => $this->sortOrder, diff --git a/src/Vendor/DirectFulfillmentShippingV20211228/Requests/GetPackingSlips.php b/src/Vendor/DirectFulfillmentShippingV20211228/Requests/GetPackingSlips.php index 390c1319..93ecd8d8 100644 --- a/src/Vendor/DirectFulfillmentShippingV20211228/Requests/GetPackingSlips.php +++ b/src/Vendor/DirectFulfillmentShippingV20211228/Requests/GetPackingSlips.php @@ -48,8 +48,8 @@ public function __construct( public function defaultQuery(): array { return array_filter([ - 'createdAfter' => $this->createdAfter?->format(\DateTime::RFC3339), - 'createdBefore' => $this->createdBefore?->format(\DateTime::RFC3339), + 'createdAfter' => $this->createdAfter?->format('Y-m-d\TH:i:s\Z'), + 'createdBefore' => $this->createdBefore?->format('Y-m-d\TH:i:s\Z'), 'shipFromPartyId' => $this->shipFromPartyId, 'limit' => $this->limit, 'sortOrder' => $this->sortOrder, diff --git a/src/Vendor/DirectFulfillmentShippingV20211228/Requests/GetShippingLabels.php b/src/Vendor/DirectFulfillmentShippingV20211228/Requests/GetShippingLabels.php index 47e2b9cf..26f793b4 100644 --- a/src/Vendor/DirectFulfillmentShippingV20211228/Requests/GetShippingLabels.php +++ b/src/Vendor/DirectFulfillmentShippingV20211228/Requests/GetShippingLabels.php @@ -48,8 +48,8 @@ public function __construct( public function defaultQuery(): array { return array_filter([ - 'createdAfter' => $this->createdAfter?->format(\DateTime::RFC3339), - 'createdBefore' => $this->createdBefore?->format(\DateTime::RFC3339), + 'createdAfter' => $this->createdAfter?->format('Y-m-d\TH:i:s\Z'), + 'createdBefore' => $this->createdBefore?->format('Y-m-d\TH:i:s\Z'), 'shipFromPartyId' => $this->shipFromPartyId, 'limit' => $this->limit, 'sortOrder' => $this->sortOrder, diff --git a/src/Vendor/OrdersV1/Requests/GetPurchaseOrders.php b/src/Vendor/OrdersV1/Requests/GetPurchaseOrders.php index 6c2cc6c0..5728015d 100644 --- a/src/Vendor/OrdersV1/Requests/GetPurchaseOrders.php +++ b/src/Vendor/OrdersV1/Requests/GetPurchaseOrders.php @@ -57,13 +57,13 @@ public function defaultQuery(): array { return array_filter([ 'limit' => $this->limit, - 'createdAfter' => $this->createdAfter?->format(\DateTime::RFC3339), - 'createdBefore' => $this->createdBefore?->format(\DateTime::RFC3339), + 'createdAfter' => $this->createdAfter?->format('Y-m-d\TH:i:s\Z'), + 'createdBefore' => $this->createdBefore?->format('Y-m-d\TH:i:s\Z'), 'sortOrder' => $this->sortOrder, 'nextToken' => $this->nextToken, 'includeDetails' => $this->includeDetails, - 'changedAfter' => $this->changedAfter?->format(\DateTime::RFC3339), - 'changedBefore' => $this->changedBefore?->format(\DateTime::RFC3339), + 'changedAfter' => $this->changedAfter?->format('Y-m-d\TH:i:s\Z'), + 'changedBefore' => $this->changedBefore?->format('Y-m-d\TH:i:s\Z'), 'poItemState' => $this->poItemState, 'isPOChanged' => $this->isPoChanged, 'purchaseOrderState' => $this->purchaseOrderState, diff --git a/src/Vendor/OrdersV1/Requests/GetPurchaseOrdersStatus.php b/src/Vendor/OrdersV1/Requests/GetPurchaseOrdersStatus.php index 166b78ff..7f46416e 100644 --- a/src/Vendor/OrdersV1/Requests/GetPurchaseOrdersStatus.php +++ b/src/Vendor/OrdersV1/Requests/GetPurchaseOrdersStatus.php @@ -61,10 +61,10 @@ public function defaultQuery(): array 'limit' => $this->limit, 'sortOrder' => $this->sortOrder, 'nextToken' => $this->nextToken, - 'createdAfter' => $this->createdAfter?->format(\DateTime::RFC3339), - 'createdBefore' => $this->createdBefore?->format(\DateTime::RFC3339), - 'updatedAfter' => $this->updatedAfter?->format(\DateTime::RFC3339), - 'updatedBefore' => $this->updatedBefore?->format(\DateTime::RFC3339), + 'createdAfter' => $this->createdAfter?->format('Y-m-d\TH:i:s\Z'), + 'createdBefore' => $this->createdBefore?->format('Y-m-d\TH:i:s\Z'), + 'updatedAfter' => $this->updatedAfter?->format('Y-m-d\TH:i:s\Z'), + 'updatedBefore' => $this->updatedBefore?->format('Y-m-d\TH:i:s\Z'), 'purchaseOrderNumber' => $this->purchaseOrderNumber, 'purchaseOrderStatus' => $this->purchaseOrderStatus, 'itemConfirmationStatus' => $this->itemConfirmationStatus, diff --git a/src/Vendor/ShipmentsV1/Requests/GetShipmentDetails.php b/src/Vendor/ShipmentsV1/Requests/GetShipmentDetails.php index 55f76c76..5d5cf309 100644 --- a/src/Vendor/ShipmentsV1/Requests/GetShipmentDetails.php +++ b/src/Vendor/ShipmentsV1/Requests/GetShipmentDetails.php @@ -83,22 +83,22 @@ public function defaultQuery(): array 'limit' => $this->limit, 'sortOrder' => $this->sortOrder, 'nextToken' => $this->nextToken, - 'createdAfter' => $this->createdAfter?->format(\DateTime::RFC3339), - 'createdBefore' => $this->createdBefore?->format(\DateTime::RFC3339), - 'shipmentConfirmedBefore' => $this->shipmentConfirmedBefore?->format(\DateTime::RFC3339), - 'shipmentConfirmedAfter' => $this->shipmentConfirmedAfter?->format(\DateTime::RFC3339), - 'packageLabelCreatedBefore' => $this->packageLabelCreatedBefore?->format(\DateTime::RFC3339), - 'packageLabelCreatedAfter' => $this->packageLabelCreatedAfter?->format(\DateTime::RFC3339), - 'shippedBefore' => $this->shippedBefore?->format(\DateTime::RFC3339), - 'shippedAfter' => $this->shippedAfter?->format(\DateTime::RFC3339), - 'estimatedDeliveryBefore' => $this->estimatedDeliveryBefore?->format(\DateTime::RFC3339), - 'estimatedDeliveryAfter' => $this->estimatedDeliveryAfter?->format(\DateTime::RFC3339), - 'shipmentDeliveryBefore' => $this->shipmentDeliveryBefore?->format(\DateTime::RFC3339), - 'shipmentDeliveryAfter' => $this->shipmentDeliveryAfter?->format(\DateTime::RFC3339), - 'requestedPickUpBefore' => $this->requestedPickUpBefore?->format(\DateTime::RFC3339), - 'requestedPickUpAfter' => $this->requestedPickUpAfter?->format(\DateTime::RFC3339), - 'scheduledPickUpBefore' => $this->scheduledPickUpBefore?->format(\DateTime::RFC3339), - 'scheduledPickUpAfter' => $this->scheduledPickUpAfter?->format(\DateTime::RFC3339), + 'createdAfter' => $this->createdAfter?->format('Y-m-d\TH:i:s\Z'), + 'createdBefore' => $this->createdBefore?->format('Y-m-d\TH:i:s\Z'), + 'shipmentConfirmedBefore' => $this->shipmentConfirmedBefore?->format('Y-m-d\TH:i:s\Z'), + 'shipmentConfirmedAfter' => $this->shipmentConfirmedAfter?->format('Y-m-d\TH:i:s\Z'), + 'packageLabelCreatedBefore' => $this->packageLabelCreatedBefore?->format('Y-m-d\TH:i:s\Z'), + 'packageLabelCreatedAfter' => $this->packageLabelCreatedAfter?->format('Y-m-d\TH:i:s\Z'), + 'shippedBefore' => $this->shippedBefore?->format('Y-m-d\TH:i:s\Z'), + 'shippedAfter' => $this->shippedAfter?->format('Y-m-d\TH:i:s\Z'), + 'estimatedDeliveryBefore' => $this->estimatedDeliveryBefore?->format('Y-m-d\TH:i:s\Z'), + 'estimatedDeliveryAfter' => $this->estimatedDeliveryAfter?->format('Y-m-d\TH:i:s\Z'), + 'shipmentDeliveryBefore' => $this->shipmentDeliveryBefore?->format('Y-m-d\TH:i:s\Z'), + 'shipmentDeliveryAfter' => $this->shipmentDeliveryAfter?->format('Y-m-d\TH:i:s\Z'), + 'requestedPickUpBefore' => $this->requestedPickUpBefore?->format('Y-m-d\TH:i:s\Z'), + 'requestedPickUpAfter' => $this->requestedPickUpAfter?->format('Y-m-d\TH:i:s\Z'), + 'scheduledPickUpBefore' => $this->scheduledPickUpBefore?->format('Y-m-d\TH:i:s\Z'), + 'scheduledPickUpAfter' => $this->scheduledPickUpAfter?->format('Y-m-d\TH:i:s\Z'), 'currentShipmentStatus' => $this->currentShipmentStatus, 'vendorShipmentIdentifier' => $this->vendorShipmentIdentifier, 'buyerReferenceNumber' => $this->buyerReferenceNumber, diff --git a/tests/SerializationTest.php b/tests/SerializationTest.php index 0cb7c511..f065d6c7 100644 --- a/tests/SerializationTest.php +++ b/tests/SerializationTest.php @@ -7,6 +7,10 @@ use Saloon\Http\Faking\MockResponse; use SellingPartnerApi\Authentication\GetAccessTokenRequest; use SellingPartnerApi\Enums\Endpoint; +use SellingPartnerApi\Seller\FBAInventoryV1\Requests\GetInventorySummaries; +use SellingPartnerApi\Seller\OrdersV0\Dto\ConfirmShipmentRequest; +use SellingPartnerApi\Seller\OrdersV0\Dto\PackageDetail; +use SellingPartnerApi\Seller\OrdersV0\Requests\ConfirmShipment; use SellingPartnerApi\Seller\ProductPricingV0\Dto\GetItemOffersBatchRequest; use SellingPartnerApi\Seller\ProductPricingV0\Dto\ItemOffersRequest; use SellingPartnerApi\Seller\ProductPricingV0\Requests\GetItemOffersBatch; @@ -83,4 +87,81 @@ public function testNullValuesAreRemovedFromSerialization(): void $mockClient->getLastPendingRequest()->body()->all() ); } + + public function testDatesInQueryParametersAreSerializedInZuluFormat(): void + { + $mockClient = new MockClient([ + GetAccessTokenRequest::class => MockResponse::make( + body: [ + 'access_token' => 'access-token', + 'refresh_token' => 'refresh-token', + 'expires_in' => 3600, + 'token_type' => 'bearer', + ], + ), + GetInventorySummaries::class => MockResponse::make(), + ]); + + $connector = SellingPartnerApi::seller( + clientId: 'client-id', + clientSecret: 'client-secret', + refreshToken: 'refresh-token', + endpoint: Endpoint::NA_SANDBOX, + ); + $connector->withMockClient($mockClient); + + $api = $connector->fbaInventoryV1(); + $api->getInventorySummaries( + granularityType: 'Marketplace', + granularityId: 'marketplace-id', + marketplaceIds: ['marketplace-id'], + startDateTime: new DateTimeImmutable('2024-01-01') + ); + + $query = $mockClient->getLastPendingRequest()->query(); + + $this->assertEquals('2024-01-01T00:00:00Z', $query->get('startDateTime')); + } + + public function testDatesInBodyParametersAreSerializedInZuluFormat(): void + { + $mockClient = new MockClient([ + GetAccessTokenRequest::class => MockResponse::make( + body: [ + 'access_token' => 'access-token', + 'refresh_token' => 'refresh-token', + 'expires_in' => 3600, + 'token_type' => 'bearer', + ], + ), + ConfirmShipment::class => MockResponse::make(), + ]); + + $connector = SellingPartnerApi::seller( + clientId: 'client-id', + clientSecret: 'client-secret', + refreshToken: 'refresh-token', + endpoint: Endpoint::NA_SANDBOX, + ); + $connector->withMockClient($mockClient); + + $api = $connector->ordersV0(); + $api->confirmShipment( + 'order-id', + new ConfirmShipmentRequest( + new PackageDetail( + packageReferenceId: 'package-reference-id', + carrierCode: 'carrier-code', + trackingNumber: 'tracking-number', + shipDate: new DateTimeImmutable('2024-01-01'), + orderItems: [], + ), + 'marketplace-id', + ) + ); + + $body = $mockClient->getLastPendingRequest()->body()->all(); + + $this->assertEquals('2024-01-01T00:00:00Z', $body['packageDetail']['shipDate']); + } }