diff --git a/src/Data/Base/ToArrayObject.php b/src/Data/Base/ToArrayObject.php index 5ebf04f9..dba550b2 100644 --- a/src/Data/Base/ToArrayObject.php +++ b/src/Data/Base/ToArrayObject.php @@ -2,6 +2,7 @@ namespace Jasara\AmznSPA\Data\Base; +use BackedEnum; use Carbon\CarbonImmutable; use Illuminate\Support\Collection; use Illuminate\Support\Str; @@ -50,8 +51,10 @@ private function mapPropertyValue( return match (true) { $has_mapper => $this->mapWithMapper($property, $value), $value instanceof Data => $this->mapWithData($case, $value), + $value instanceof TypedCollection => $value->toArrayObject(), $value instanceof Collection => $this->mapWithCollection($case, $value), $value instanceof CarbonImmutable => $this->mapWithCarbonImmutable($value), + $value instanceof BackedEnum => $value->value, default => $value, }; } diff --git a/src/Data/Base/TypedCollection.php b/src/Data/Base/TypedCollection.php index 61fc7ef7..f8308cc6 100644 --- a/src/Data/Base/TypedCollection.php +++ b/src/Data/Base/TypedCollection.php @@ -2,6 +2,7 @@ namespace Jasara\AmznSPA\Data\Base; +use BackedEnum; use Illuminate\Support\Arr; use Illuminate\Support\Collection; @@ -54,4 +55,17 @@ public function reduce(callable $callback, $initial = null) { return $this->toBase()->reduce($callback, $initial); } + + public function toArrayObject(): \ArrayObject + { + return new \ArrayObject($this->map(function ($item) { + return match (true) { + $item instanceof TypedCollection => $item->toArrayObject(), + $item instanceof Collection => $item->toArrayObject(), + $item instanceof Data => $item->toArrayObject(), + $item instanceof BackedEnum => $item->value, + default => $item, + }; + })->toArray()); + } } diff --git a/src/Data/Responses/FulfillmentInbound/v20240320/ListPrepDetailsResponse.php b/src/Data/Responses/FulfillmentInbound/v20240320/ListPrepDetailsResponse.php new file mode 100644 index 00000000..65db5521 --- /dev/null +++ b/src/Data/Responses/FulfillmentInbound/v20240320/ListPrepDetailsResponse.php @@ -0,0 +1,14 @@ + + */ +class MskuPrepDetailInputSchemaList extends TypedCollection +{ + public const ITEM_CLASS = MskuPrepDetailInputSchema::class; +} diff --git a/src/Data/Schemas/FulfillmentInbound/v20240320/MskuPrepDetailSchema.php b/src/Data/Schemas/FulfillmentInbound/v20240320/MskuPrepDetailSchema.php new file mode 100644 index 00000000..8e20e600 --- /dev/null +++ b/src/Data/Schemas/FulfillmentInbound/v20240320/MskuPrepDetailSchema.php @@ -0,0 +1,18 @@ + + */ +class MskuPrepDetailSchemaList extends TypedCollection +{ + public const ITEM_CLASS = MskuPrepDetailSchema::class; +} diff --git a/src/Data/Schemas/FulfillmentInbound/v20240320/OwnerConstraint.php b/src/Data/Schemas/FulfillmentInbound/v20240320/OwnerConstraint.php new file mode 100644 index 00000000..3c009dfd --- /dev/null +++ b/src/Data/Schemas/FulfillmentInbound/v20240320/OwnerConstraint.php @@ -0,0 +1,10 @@ + + */ +class PrepTypeList extends TypedCollection +{ + public const ITEM_CLASS = PrepType::class; +} diff --git a/src/Resources/FulfillmentInbound/FulfillmentInbound20240320Resource.php b/src/Resources/FulfillmentInbound/FulfillmentInbound20240320Resource.php index d5369f29..c721dfe9 100644 --- a/src/Resources/FulfillmentInbound/FulfillmentInbound20240320Resource.php +++ b/src/Resources/FulfillmentInbound/FulfillmentInbound20240320Resource.php @@ -52,6 +52,7 @@ use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\ListPackingGroupItemsResponse; use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\ListPackingOptionsResponse; use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\ListPlacementOptionsResponse; +use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\ListPrepDetailsResponse; use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\ListShipmentBoxesResponse; use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\ListShipmentContentUpdatePreviewsResponse; use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\ListShipmentItemsResponse; @@ -59,12 +60,14 @@ use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\ListTransportationOptionsResponse; use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\ScheduleSelfShipAppointmentResponse; use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\SetPackingInformationResponse; +use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\SetPrepDetailsResponse; use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\UpdateItemComplianceDetailsResponse; use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\UpdateShipmentDeliveryWindowResponse; use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\UpdateShipmentSourceAddressResponse; use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\UpdateShipmentTrackingDetailsResponse; use Jasara\AmznSPA\Data\Schemas\Common\SortOrder; use Jasara\AmznSPA\Data\Schemas\FulfillmentInbound\v20240320\InboundPlanStatus; +use Jasara\AmznSPA\Data\Schemas\FulfillmentInbound\v20240320\MskuPrepDetailInputSchemaList; use Jasara\AmznSPA\Data\Schemas\FulfillmentInbound\v20240320\SortBy; use Jasara\AmznSPA\Traits\ValidatesParameters; @@ -525,7 +528,7 @@ public function listPackingGroupItems( ->responseClass(ListPackingGroupItemsResponse::class) ->get( $this->endpoint . self::BASE_PATH . 'inboundPlans/' . $inbound_plan_id - . '/packingGroups/' . $packing_group_id + . '/packingGroups/' . $packing_group_id . '/items', array_filter([ 'pageSize' => $page_size, @@ -861,4 +864,37 @@ public function getInboundOperationStatus( return $response; } + + public function listPrepDetails( + string $marketplace_id, + #[RuleValidator(['min:1', 'max:100'])] + array $mskus, + ): ListPrepDetailsResponse { + $this->validateAttributes(__FUNCTION__, ...func_get_args()); + + $response = $this->http + ->responseClass(ListPrepDetailsResponse::class) + ->get($this->endpoint . self::BASE_PATH . 'prepDetails', [ + 'marketplaceId' => $marketplace_id, + 'mskus' => $mskus, + ]); + + return $response; + } + + public function setPrepDetails( + string $marketplace_id, + MskuPrepDetailInputSchemaList $msku_prep_details, + ): SetPrepDetailsResponse { + $this->validateAttributes(__FUNCTION__, ...func_get_args()); + + $response = $this->http + ->responseClass(SetPrepDetailsResponse::class) + ->post($this->endpoint . self::BASE_PATH . 'items/prepDetails', [ + 'marketplaceId' => $marketplace_id, + 'mskuPrepDetails' => $msku_prep_details->toArrayObject(), + ]); + + return $response; + } } diff --git a/tests/Unit/Resources/FulfillmentInbound/FulfillmentInbound20240320ResourceTest.php b/tests/Unit/Resources/FulfillmentInbound/FulfillmentInbound20240320ResourceTest.php index db21c60b..3d3e41f3 100644 --- a/tests/Unit/Resources/FulfillmentInbound/FulfillmentInbound20240320ResourceTest.php +++ b/tests/Unit/Resources/FulfillmentInbound/FulfillmentInbound20240320ResourceTest.php @@ -50,6 +50,7 @@ use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\ListPackingGroupItemsResponse; use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\ListPackingOptionsResponse; use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\ListPlacementOptionsResponse; +use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\ListPrepDetailsResponse; use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\ListShipmentBoxesResponse; use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\ListShipmentContentUpdatePreviewsResponse; use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\ListShipmentItemsResponse; @@ -57,10 +58,16 @@ use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\ListTransportationOptionsResponse; use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\ScheduleSelfShipAppointmentResponse; use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\SetPackingInformationResponse; +use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\SetPrepDetailsResponse; use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\UpdateItemComplianceDetailsResponse; use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\UpdateShipmentDeliveryWindowResponse; use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\UpdateShipmentSourceAddressResponse; use Jasara\AmznSPA\Data\Responses\FulfillmentInbound\v20240320\UpdateShipmentTrackingDetailsResponse; +use Jasara\AmznSPA\Data\Schemas\FulfillmentInbound\v20240320\MskuPrepDetailInputSchema; +use Jasara\AmznSPA\Data\Schemas\FulfillmentInbound\v20240320\MskuPrepDetailInputSchemaList; +use Jasara\AmznSPA\Data\Schemas\FulfillmentInbound\v20240320\PrepCategory; +use Jasara\AmznSPA\Data\Schemas\FulfillmentInbound\v20240320\PrepType; +use Jasara\AmznSPA\Data\Schemas\FulfillmentInbound\v20240320\PrepTypeList; use Jasara\AmznSPA\Resources\FulfillmentInbound\FulfillmentInbound20240320Resource; use Jasara\AmznSPA\Tests\Unit\UnitTestCase; use PHPUnit\Framework\Attributes\CoversClass; @@ -1087,4 +1094,64 @@ public function testCreateMarketplaceItemLabels(): void return true; }); } + + public function testListPrepDetails(): void + { + [$config, $http] = $this->setupConfigWithFakeHttp('fulfillment-inbound/v20240320/list-prep-details'); + + $mskus = ['msku1', 'msku2']; + + $amzn = new AmznSPA($config); + $amzn = $amzn->usingMarketplace('ATVPDKIKX0DER'); + $response = $amzn->fulfillment_inbound20240320->listPrepDetails( + marketplace_id: 'ATVPDKIKX0DER', + mskus: $mskus, + ); + + $this->assertInstanceOf(ListPrepDetailsResponse::class, $response); + $this->assertEquals('msku1', $response->msku_prep_details[0]->msku); + + $http->assertSent(function (Request $request) use ($mskus) { + $this->assertEquals('GET', $request->method()); + $this->assertEquals('https://sellingpartnerapi-na.amazon.com/inbound/fba/2024-03-20/prepDetails?marketplaceId=ATVPDKIKX0DER&mskus=msku1,msku2', urldecode($request->url())); + + return true; + }); + } + + public function testSetPrepDetails(): void + { + [$config, $http] = $this->setupConfigWithFakeHttp('fulfillment-inbound/v20240320/set-prep-details'); + + $msku_prep_details = MskuPrepDetailInputSchemaList::make([ + new MskuPrepDetailInputSchema( + msku: 'msku1', + prep_category: PrepCategory::Sharp, + prep_types: PrepTypeList::make([ + PrepType::Sharp, + ]), + ), + ]); + + $amzn = new AmznSPA($config); + $amzn = $amzn->usingMarketplace('ATVPDKIKX0DER'); + $response = $amzn->fulfillment_inbound20240320->setPrepDetails( + marketplace_id: 'ATVPDKIKX0DER', + msku_prep_details: $msku_prep_details, + ); + + $this->assertInstanceOf(SetPrepDetailsResponse::class, $response); + $this->assertEquals('1234abcd-1234-abcd-5678-1234abcd1102', $response->operation_id); + + $http->assertSent(function (Request $request) use ($msku_prep_details) { + $this->assertEquals('POST', $request->method()); + $this->assertEquals('https://sellingpartnerapi-na.amazon.com/inbound/fba/2024-03-20/items/prepDetails', (string) $request->url()); + $this->assertEquals('ATVPDKIKX0DER', $request->data()['marketplaceId']); + ray($request->data()); + $this->assertEquals('SHARP', $request->data()['mskuPrepDetails'][0]['prepCategory']); + $this->assertEquals('SHARP', $request->data()['mskuPrepDetails'][0]['prepTypes'][0]); + + return true; + }); + } } diff --git a/tests/stubs/fulfillment-inbound/v20240320/list-prep-details.json b/tests/stubs/fulfillment-inbound/v20240320/list-prep-details.json new file mode 100644 index 00000000..2a9182d7 --- /dev/null +++ b/tests/stubs/fulfillment-inbound/v20240320/list-prep-details.json @@ -0,0 +1,24 @@ +{ + "mskuPrepDetails": [ + { + "msku": "msku1", + "prepCategory": "TEXTILE", + "prepTypes": [ + "ITEM_LABELING", + "ITEM_POLYBAGGING" + ], + "prepOwnerConstraint": "AMAZON_ONLY", + "labelOwnerConstraint": "AMAZON_ONLY", + "allOwnersConstraint": "MUST_MATCH" + }, + { + "msku": "msku2", + "prepCategory": "FRAGILE", + "prepTypes": [ + "ITEM_LABELING", + "ITEM_BUBBLEWRAP" + ], + "allOwnersConstraint": "MUST_MATCH" + } + ] +} \ No newline at end of file diff --git a/tests/stubs/fulfillment-inbound/v20240320/set-prep-details.json b/tests/stubs/fulfillment-inbound/v20240320/set-prep-details.json new file mode 100644 index 00000000..43590c04 --- /dev/null +++ b/tests/stubs/fulfillment-inbound/v20240320/set-prep-details.json @@ -0,0 +1,3 @@ +{ + "operationId": "1234abcd-1234-abcd-5678-1234abcd1102" +} \ No newline at end of file