From d1aa0d679c22229b5c604eff17aeb6559da75dad Mon Sep 17 00:00:00 2001 From: Rhys Hall Date: Sat, 13 Jul 2024 16:18:55 +1000 Subject: [PATCH] v1.0 --- CHANGELOG.md | 10 +- README.md | 131 ++++- composer.json | 4 +- src/Collection.php | 5 + src/Etsy.php | 157 +---- src/OAuth/Client.php | 40 +- src/Resource.php | 75 ++- src/Resources/BuyerTaxonomy.php | 28 + src/Resources/BuyerTaxonomyProperty.php | 31 + src/Resources/HolidayPreference.php | 81 +++ src/Resources/LedgerEntry.php | 68 ++- src/Resources/Listing.php | 704 ++++++++++++++--------- src/Resources/ListingFile.php | 77 ++- src/Resources/ListingImage.php | 73 ++- src/Resources/ListingInventory.php | 66 ++- src/Resources/ListingOffering.php | 23 +- src/Resources/ListingProduct.php | 41 +- src/Resources/ListingProperty.php | 95 ++- src/Resources/ListingTranslation.php | 95 ++- src/Resources/ListingVariationImage.php | 44 +- src/Resources/ListingVideo.php | 88 +++ src/Resources/Payment.php | 65 ++- src/Resources/ProductionPartner.php | 31 + src/Resources/Receipt.php | 151 +++-- src/Resources/ReturnPolicy.php | 165 ++++++ src/Resources/Review.php | 41 +- src/Resources/SellerTaxonomy.php | 28 + src/Resources/SellerTaxonomyProperty.php | 30 + src/Resources/Shipment.php | 26 +- src/Resources/ShippingCarrier.php | 22 +- src/Resources/ShippingDestination.php | 122 +++- src/Resources/ShippingProfile.php | 215 +++++-- src/Resources/ShippingUpgrade.php | 117 +++- src/Resources/Shop.php | 485 ++++++++-------- src/Resources/ShopSection.php | 148 ++++- src/Resources/Taxonomy.php | 28 - src/Resources/TaxonomyProperty.php | 13 - src/Resources/Transaction.php | 79 ++- src/Resources/User.php | 65 ++- src/Resources/UserAddress.php | 54 +- 40 files changed, 2854 insertions(+), 967 deletions(-) create mode 100644 src/Resources/BuyerTaxonomy.php create mode 100644 src/Resources/BuyerTaxonomyProperty.php create mode 100644 src/Resources/HolidayPreference.php create mode 100644 src/Resources/ListingVideo.php create mode 100644 src/Resources/ProductionPartner.php create mode 100644 src/Resources/ReturnPolicy.php create mode 100644 src/Resources/SellerTaxonomy.php create mode 100644 src/Resources/SellerTaxonomyProperty.php delete mode 100644 src/Resources/Taxonomy.php delete mode 100644 src/Resources/TaxonomyProperty.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 38d1377..a63b712 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,15 +2,7 @@ ## v1.0 ### Changes -* Added `$date_from` and `$date_to` params to the `Shop::getLedgerEntries` method. These params expect either a unix timestamp or an instance of DateTime. If left empty or set to false they will default to the past 7 days. -* Added `linkFile` method to the Listing resource. Removed support for linking a file from the `uploadFile` method. -* Added `linkImage` method to the Listing resource. Removed support for linking an image from the `uploadImage` method. -* Added `$file`, `$name` and `$rank` params to the `Listing::uploadFile` method. Removed the `$data` param. -* Added `$file`, `$name`, `$rank` and `$options` params to the `Listing::uploadImage` method. Removed the `$data` param. -* Removed the `Listing::updateInventory` method. This has been replaced with `ListingInventory::update`. - -### Fixed issues -* UploadFile request was throwing an exception if 'image' parameter was missing. This check has been removed. +* Everything. Unfortunately, this is a breaking update. ## v0.3.2 ### Fixed issues diff --git a/README.md b/README.md index 0b080f6..826e50c 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,12 @@ # Etsy PHP SDK A PHP SDK for the Etsy API v3. -This package is still in development. +**Major update on the 13th July 2024. This fixed all major issues and adds resources for recent additions to the API. If you are upgrading from a version prior to this - consider the whole thing to be breaking. There is no upgrade path and you will need to review all your code.** + +Proper documentation still to come. Want to write it for me? I'll buy you an iced latte. ## Requirements -PHP 7.1 or greater. +PHP 8 or greater. ## Install Install the package using composer. @@ -12,10 +14,16 @@ Install the package using composer. composer require rhysnhall/etsy-php-sdk ``` -Include the OAuth client and Etsy class. +Include the Etsy class. ```php use Etsy\Etsy; -use Etsy\OAuth\Client; + +$etsy = new Etsy( + $client_id, + $access_token +); + +// Do the Etsy things. ``` ## Usage @@ -25,7 +33,7 @@ The Etsy API uses OAuth 2.0 authentication. You can read more about authenticati The first step in OAuth2 is to request an OAuth token. You will need an existing App API key which you can obtained by registering an app [here](https://www.etsy.com/developers/register). ```php -$client = new Etsy\OAuth\Client($api_key); +$client = new Etsy\OAuth\Client($client_id); ``` Generate a URL to redirect the user to authorize access to your app. @@ -89,7 +97,7 @@ You'll be provided with both an access token and a refresh token. The access tok #### Refreshing your token -You can refresh your authorization token using the refresh token that was previously provided. This will provide you with a new valid access token and another refresh token. +You can refresh your authorization token (even after it has expired) using the refresh token that was previously provided. This will provide you with a new valid access token and another refresh token. ```php [$access_token, $refresh_token] = $client->refreshAccessToken($refresh_token); @@ -107,37 +115,118 @@ This will provide you with a brand new set of OAuth2 access and refresh tokens. ### Basic use -Create a new instance of the Etsy class using your App API key and a user's access token. +Create a new instance of the Etsy class using your App API key and a user's access token. **You must always initialize the Etsy resource before calling any resources**. + +```php +use Etsy\Etsy; +use Etsy\Resources\User; + +$etsy = new Etsy($apiKey, $accessToken); + +// Get the authenticated user. +$user = User::me(); + +// Get the users shop. +$shop = $user->shop(); +``` + +#### Resources +Most calls will return a `Resource`. Resources contain a number of methods that streamline your interaction with the Etsy API. +```php +// Get a Listing Resource +$listing = \Etsy\Resources\Listing::get($shopId); +``` +Resources contain the API response from Etsy as properties. ```php -$etsy = new Etsy\Etsy($api_key, $access_token); +$listingTitle = $listing->title; +``` -// Get user. -$user = $etsy->getUser(); +##### Associations +Resources will return associations as their respective Resource when appropriate. For example the bellow call will return the `shop` property as an instance of `Etsy\Resources\Shop`. +```php +$shop = $listing->shop; +``` -// Get shop. -$shop = $user->getShop(); +##### `toJson` +The `toJson` method will return the Resource as a JSON encoded object. +```php +$json = $listing->toJson(); +``` -// Update shop. -$shop->update([ - 'title' => 'My exciting shop!' -]); +##### `toArray` +The `toArray` method will return the Resource as an array. +```php +$array = $listing->toArray(); ``` -###### Collections +#### Collections When there is more than one result a collection will be returned. ```php -$reviews = $shop->getReviews(); +$reviews = Review::all(); +``` + +Results are stored as an array of `Resource` the `data` property of the collection. +```php +$firstReview = $reviews->data[0]; +``` -// Get first review. -$first = $reviews->first(); +Collections contain a handful of useful methods. +##### `first` +Get the first item in the collection. +```php +$firstReview = $reviews->first(); +``` + +##### `count` +Get the number of results in the collection. Not be confused with the `count` property which displays the number of results in a full Etsy resource. +```php +$count = $reviews->count(); +``` + +##### `append` +Append a property to each item in the collection. +```php +$reviews->append(['shop_id' => $shopId]); +``` + +##### `paginate` +Most Etsy methods are capped at 100 results per call. You can use the `paginate` method to get more results than this (up to 500 results). +```php // Get 100 results using pagination. -foreach($reviews->paginate(100) as $review) { +foreach($reviews->paginate(200) as $review) { ... } ``` +##### `toJson` +Returns the items in the collection as an array of JSON strings. +```php +$jsonArray = $reviews->toJson(); +``` + +#### Direct Requests +You can make direct requests to the Etsy API using the static `$client` property of the Etsy class. + +```php +$response = Etsy::$client->get( + "/application/listings/active", + [ + "limit" => 25 + ] +); +``` + +If you still want to use the Resources classes you can convert the response into a Resource. + +```php +$listings = Etsy::getResource( + $response, + 'Listing' +); +``` + --- Full documentation will be available soon. Email [hello@rhyshall.com](mailto:hello@rhyshall.com) for any assistance. diff --git a/composer.json b/composer.json index 12200e0..1442fe9 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "rhysnhall/etsy-php-sdk", - "version": "0.3.2", + "version": "1.0", "description": "PHP SDK for Etsy API v3.", "type": "library", "keywords": [ @@ -18,7 +18,7 @@ } ], "require": { - "php": ">=7.1", + "php": "^8.0", "guzzlehttp/guzzle": "^7.3" }, "autoload": { diff --git a/src/Collection.php b/src/Collection.php index cc80867..2e1d483 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -37,6 +37,11 @@ class Collection { */ protected $_append = []; + /** + * @var int + */ + public $count = 0; + /** * @var array */ diff --git a/src/Etsy.php b/src/Etsy.php index d97bbbd..61e1fc4 100644 --- a/src/Etsy.php +++ b/src/Etsy.php @@ -29,13 +29,15 @@ class Etsy { public function __construct( string $client_id, - string $api_key, + ?string $api_key = null, array $config = [] ) { $this->client_id = $client_id; $this->api_key = $api_key; static::$client = new Client($client_id); - static::$client->setApiKey($api_key); + if($api_key) { + static::$client->setApiKey($api_key); + } static::$client->setConfig($config); } @@ -67,6 +69,9 @@ public static function createCollection( string $resource ) { $collection = new Collection($resource, $response->uri); + if(isset($response->count)) { + $collection->count = $response->count; + } if(!count($response->results) || !isset($response->results)) { return $collection; } @@ -107,150 +112,12 @@ public static function createResource( } /** - * Check to confirm connectivity to the Etsy API with an application - * - * @link https://developers.etsy.com/documentation/reference#operation/ping - * @return integer|false - */ - public function ping() { - $response = static::$client->get("/application/openapi-ping"); - return $response->application_id ?? false; - } - - /** - * Only supports getting the user for who the current API KEY is associated with. - * - * @return Etsy\Resources\User - */ - public function getUser() { - $user_id = explode(".", $this->api_key)[0]; - $response = static::$client->get("/application/users/{$user_id}"); - return static::getResource($response, "User"); - } - - /** - * Gets an Etsy shop. If no shop_id is specified the current user will be queried for an associated shop. - * - * @param int $shop_id - * @return Etsy\Resources\Shop - */ - public function getShop( - int $shop_id = null - ) { - if(!$shop_id) { - return $this->getUser()->getShop(); - } - $response = static::$client->get("/application/shops/{$shop_id}"); - return static::getResource($response, "Shop"); - } - - /** - * Search for shops using a keyword. - * - * @param string $keyword - * @param array $params - * @return Etsy\Collection[Etsy\Resources\Shop] - */ - public function getShops($keyword, $params = []) { - if(!strlen(trim($keyword))) { - throw new ApiException("You must specify a keyword when searching for Etsy shops."); - } - $params['shop_name'] = $keyword; - $response = static::$client->get( - "/application/shops", - $params - ); - return static::getResource($response, "Shop"); - } - - /** - * Retrieves the full hierarchy tree of seller taxonomy nodes. - * - * @return Etsy\Collection[Etsy\Resources\Taxonomy] + * Check the permission scopes for the current Etsy user. + * + * @return array */ - public function getSellerTaxonomy() { - $response = static::$client->get( - "/application/seller-taxonomy/nodes" - ); - return static::getResource($response, "Taxonomy"); - } - - /** - * Retrieves a list of available shipping carriers and the mail classes associated with them for a given country - * - * @param string $iso_code - * @return Etsy\Collection[Etsy\Resources\ShippingCarrier] - */ - public function getShippingCarriers($iso_code) { - $response = static::$client->get( - "/application/shipping-carriers", - [ - "origin_country_iso" => $iso_code - ] - ); - return static::getResource($response, "ShippingCarrier"); - } - - /** - * Gets an individual listing on Etsy. - * - * @link https://developers.etsy.com/documentation/reference#operation/getListing - * @param integer|string $listing_id - * @param array $includes - * @return Etsy\Resources\Listing - */ - public function getListing( - $listing_id, - array $includes = [] - ) { - $response = static::$client->get( - "/application/listings/{$listing_id}", - [ - 'includes' => $includes - ] - ); - return static::getResource($response, "Listing"); - } - - /** - * Gets all public listings on Etsy. Filter with keyword param. - * - * @link https://developers.etsy.com/documentation/reference#operation/findAllListingsActive - * @param array $params - * @return Etsy\Collection[Etsy\Resources\Listing] - */ - public function getPublicListings(array $params = []) { - $response = static::$client->get( - "/application/listings/active", - $params - ); - return static::getResource($response, "Listing"); - } - - /** - * Get the specified Etsy listings. Supports a maximum of 100 listing IDs. - * - * @link https://developers.etsy.com/documentation/reference#operation/getListingsByListingIds - * @param array $listing_ids - * @param array $includes - * @return Etsy\Collection[Etsy\Resources\Listing] - */ - public function getListings( - array $listing_ids, - array $includes = [] - ) { - if(!count($listing_ids) - || count($listing_ids) > 100) { - throw new ApiException("Query requires at least one listing ID and cannot exceed a maximum of 100 listing IDs."); - } - $response = static::$client->get( - "/application/listings/batch", - [ - "listing_ids" => $listing_ids, - "includes" => $includes - ] - ); - return static::getResource($response, "Listing"); + public function scopes(): array { + return static::$client->scopes($this->api_key); } } diff --git a/src/OAuth/Client.php b/src/OAuth/Client.php index a6cd261..42948be 100644 --- a/src/OAuth/Client.php +++ b/src/OAuth/Client.php @@ -39,6 +39,11 @@ class Client { */ protected $config = []; + /** + * @var array + */ + protected $headers = []; + /** * Create a new instance of Client. * @@ -52,6 +57,7 @@ public function __construct( throw new OAuthException("No client ID found. A valid client ID is required."); } $this->client_id = $client_id; + $this->headers['x-api-key'] = $client_id; } /** @@ -80,10 +86,7 @@ public function setConfig($config) { * @return void */ public function setApiKey($api_key) { - $this->headers = [ - 'x-api-key' => $this->client_id, - 'Authorization' => "Bearer {$api_key}" - ]; + $this->headers['Authorization'] = "Bearer {$api_key}"; } public function __call($method, $args) { @@ -98,7 +101,7 @@ public function __call($method, $args) { if($method == 'get' && count($args[1] ?? [])) { $uri .= "?".RequestUtil::prepareParameters($args[1]); } - if(in_array($method, ['post', 'put'])) { + if(in_array($method, ['post', 'put', 'patch'])) { if($file = RequestUtil::prepareFile($args[1] ?? [])) { $opts['multipart'] = $file; } @@ -321,4 +324,31 @@ private function base64Encode($string) { "+/", "-_" ); } + + /** + * Check to confirm connectivity to the Etsy API. + * + * @link https://developers.etsy.com/documentation/reference#operation/ping + * @return integer|false + */ + public function ping() { + $response = $this->get("/application/openapi-ping"); + return $response->application_id ?? false; + } + + /** + * Check the scopes of the current API key (client ID). + * + * @link https://developers.etsy.com/documentation/reference/#operation/tokenScopes + * @param string $token + * @return array + */ + public function scopes( + string $token + ): array { + $response = $this->post('/application/scopes', [ + 'token' => $token + ]); + return $response->scopes ?? []; + } } diff --git a/src/Resource.php b/src/Resource.php index 7ea028d..c8ffb2e 100644 --- a/src/Resource.php +++ b/src/Resource.php @@ -21,11 +21,21 @@ class Resource { */ protected $_rename = []; + /** + * @var array + */ + protected $_saveable = []; + /** * @var array */ protected $_properties = []; + /** + * @var array + */ + private $_originalState = []; + /** * Constructor method for the Resource class. * @@ -34,6 +44,8 @@ class Resource { */ public function __construct($properties = false) { if($properties) { + $this->_properties = $properties; + $this->_originalState = $this->toArray(); $properties = $this->renameProperties($properties); $properties = $this->linkAssociations($properties); } @@ -90,6 +102,7 @@ public function __set($property, $value) { */ protected function linkAssociations($properties) { foreach($this->_associations as $association => $resource) { + $association = strtolower($association); if(isset($properties->$association)) { if(is_array($properties->$association)) { $properties->$association = Etsy::createCollectionResources( @@ -141,6 +154,7 @@ protected function updateRequest(string $url, array $data, $method = "PUT") { ); // Update the existing properties. $properties = get_object_vars($result)['_properties']; + $this->_originalState = $result->_originalState; foreach($properties as $property => $value) { if(isset($this->_properties->{$property})) { $this->_properties->{$property} = $value; @@ -157,7 +171,7 @@ protected function updateRequest(string $url, array $data, $method = "PUT") { * @param string $data * @return boolean */ - protected function deleteRequest(string $url, array $data = []) { + protected static function deleteRequest(string $url, array $data = []) { $response = Etsy::$client->delete( $url, $data @@ -174,7 +188,7 @@ protected function deleteRequest(string $url, array $data = []) { * @param array $params * @return Collection */ - protected function request( + public static function request( string $method, string $url, string $resource, @@ -220,4 +234,61 @@ public function toArray() { return $array; } + /** + * Get the saveable data. + * + * @return array + */ + protected function getSaveData($patch = false) { + if($patch) { + $changed = $this->getChanged( + $this->toArray(), + $this->_originalState + ); + } + else { + $changed = $this->toArray(); + } + $data = []; + foreach($this->_saveable as $key) { + if(isset($changed[$key])) { + $data[$key] = $changed[$key]; + } + } + return $data; + } + + /** + * Get the properties which have changed. + * + * @param array $arrayOne + * @param array @arrayTwo + * @return array + */ + private function getChanged( + array $arrayOne, + array $arrayTwo + ): array { + $changed = []; + foreach($arrayOne as $key => $value) { + if(array_key_exists($key, $arrayTwo)) { + if(is_array($value)) { + $recursiveChanged = self::getChanged($arrayTwo[$key], $value); + if(count($recursiveChanged)) { + $changed[$key] = $recursiveChanged; + } + } + else { + if($value != $arrayTwo[$key]) { + $changed[$key] = $value; + } + } + } + else { + $changed[$key] = $value; + } + } + return $changed; + } + } diff --git a/src/Resources/BuyerTaxonomy.php b/src/Resources/BuyerTaxonomy.php new file mode 100644 index 0000000..f6b480d --- /dev/null +++ b/src/Resources/BuyerTaxonomy.php @@ -0,0 +1,28 @@ +getSaveData(); + } + if(count($data) == 0) { + return $this; + } + return $this->updateRequest( + "/application/shops/{$this->shop_id}/holiday-preferences/{$this->holiday_id}", + $data + ); + } + +} diff --git a/src/Resources/LedgerEntry.php b/src/Resources/LedgerEntry.php index 7a9496b..6be259d 100644 --- a/src/Resources/LedgerEntry.php +++ b/src/Resources/LedgerEntry.php @@ -3,6 +3,8 @@ namespace Etsy\Resources; use Etsy\Resource; +use Etsy\Utils\Date; +use Etsy\Resources\Payment; /** * LedgerEntry resource class. Represents an entry in an Etsy shop's ledger. @@ -13,18 +15,64 @@ class LedgerEntry extends Resource { /** - * Get the payment associated with this ledger entry. - * - * @return \Etsy\Resources\Payment + * Get all ledger entries for a shop. + * + * @param int $shop_id + * @param array $params + * @return Etsy\Collection[Etsy\Resources\LedgerEntry] */ - public function getPayment() { - return $this->request( + public static function all( + int $shop_id, + array $params = [] + ): \Etsy\Collection { + // Default period is 7 days. If either is not set, or only one set we override with the default. + if(!isset($params['min_created']) || !isset($params['max_created'])) { + $params['min_created'] = Date::now()->modify('-1 week')->getTimestamp(); + $params['max_created'] = Date::now()->getTimestamp(); + } + if($params['min_created'] instanceof \DateTime) { + $params['min_created'] = $params['min_created']->getTimestamp(); + } + if($params['max_created'] instanceof \DateTime) { + $params['max_created'] = $params['max_created']->getTimestamp(); + } + return self::request( "GET", - "/application/shops/{$this->shop_id}/payment-account/ledger-entries/payments", - "Payment", - ["ledger_entry_ids" => [$this->entry_id]] - ) - ->first(); + "/application/shops/{$shop_id}/payment-account/ledger-entries", + "LedgerEntry", + $params + )->append(['shop_id', $shop_id]); + } + + /** + * Get a single ledger entry. + * + * @param int $shop_id + * @param int $ledger_entry_id + * @return Etsy\Resources\LedgerEntry + */ + public static function get( + int $shop_id, + int $ledger_entry_id + ): ?\Etsy\Resources\LedgerEntry { + $entry = self::request( + "GET", + "/application/shops/{$shop_id}/payment-account/ledger-entries/{$ledger_entry_id}", + "LedgerEntry" + ); + if($entry) { + $entry->shop_id = $shop_id; + } + return $entry; + } + + /** + * Get payments for the ledger entry. + * + * @return \Etsy\Collection[Etsy\Resources\Payment] + */ + public function payments(): \Etsy\Collection { + return Payment::allByLedgerEntries($this->shop_id, [$this->entry_id]); } } diff --git a/src/Resources/Listing.php b/src/Resources/Listing.php index 6a61cf3..d78c57c 100644 --- a/src/Resources/Listing.php +++ b/src/Resources/Listing.php @@ -4,6 +4,18 @@ use Etsy\Resource; use Etsy\Exception\ApiException; +use Etsy\Resources\{ + Review, + Transaction, + ListingProperty, + ListingFile, + ListingImage, + ListingVideo, + ListingVariationImage, + ListingInventory, + ListingProduct, + ListingTranslation +}; /** * Listing resource class. Represents an Etsy listing. @@ -13,383 +25,529 @@ */ class Listing extends Resource { + /** + * @var array + */ + protected $_saveable = [ + 'image_ids', + 'title', + 'description', + 'materials', + 'should_auto_renew', + 'shipping_profile_id', + 'return_policy_id', + 'shop_section_id', + 'item_weight', + 'item_length', + 'item_width', + 'item_height', + 'item_weight_unit', + 'item_dimensions_unit', + 'is_taxable', + 'taxonomy_id', + 'tags', + 'who_made', + 'when_made', + 'featured_rank', + 'is_personalizable', + 'personalization_is_required', + 'personalization_char_count_max', + 'personalization_instructions', + 'state', + 'is_supply', + 'production_partner_ids', + 'type' + ]; + /** * @var array */ protected $_associations = [ "Shop" => "Shop", "User" => "User", - "Images" => "Image" + "Images" => "ListingImage" ]; /** - * Update the Etsy listing. - * - * @link https://developers.etsy.com/documentation/reference#operation/updateListing - * @param array $data - * @return Etsy\Resources\Listing + * Get all active listings on Etsy. + * + * @param array $params + * @return \Etsy\Collection[Etsy\Resources\Listing] */ - public function update(array $data) { - return $this->updateRequest( - "/application/shops/{$this->shop_id}/listings/{$this->listing_id}", - $data + public static function all( + array $params = [] + ): \Etsy\Collection { + return self::request( + "GET", + "/application/listings/active", + "Listing", + $params ); } /** - * Delete the listing. - * - * @link https://developers.etsy.com/documentation/reference#operation/deleteListing - * @return boolean + * Get all active listings on Etsy. Filtered by listing ID. Support upto 100 IDs. + * + * @param array $params + * @return \Etsy\Collection[Etsy\Resources\Listing] */ - public function delete() { - return $this->deleteRequest( - "/application/shops/{$this->shop_id}/listings/{$this->listing_id}" + public static function allByIds( + string|array $listing_ids, + array $includes = [] + ): \Etsy\Collection { + $params = [ + 'listing_ids' => $listing_ids + ]; + if(count($includes) > 0) { + $params['includes'] = $includes; + } + return self::request( + "GET", + "/application/listings/batch", + "Listing", + $params ); } /** - * Get the listing properties associated with the listing. - * - * @link https://developers.etsy.com/documentation/reference#operation/getListingProperties - * @return Etsy\Collection[Etsy\Resources\ListingProperty] + * Get all listings for a shop. + * + * @param int $shop_id + * @param array $params + * @return \Etsy\Collection[Etsy\Resources\Listing] */ - public function getListingProperties() { - return $this->request( + public static function allByShop( + int $shop_id, + array $params = [] + ): \Etsy\Collection { + return self::request( "GET", - "/application/shops/{$this->shop_id}/listings/{$this->listing_id}/properties", - "ListingProperty" - ) - ->append([ - 'shop_id' => $this->shop_id, - 'listing_id' => $this->listing_id - ]); + "/application/shops/{$shop_id}/listings", + "Listing", + $params + ); } /** - * Get a specific listing property. - * - * @NOTE This method is not ready for use and will return a 501 repsonse. - * @link https://developers.etsy.com/documentation/reference#operation/getListingProperty - * @param integer|string $property_id - * @return Etsy\Resources\ListingProperty + * Get all active listings for a shop. + * + * @param int $shop_id + * @param array $params + * @return \Etsy\Collection[Etsy\Resources\Listing] */ - public function getListingProperty($property_id) { - $listing_property = $this->request( + public static function allActiveByShop( + int $shop_id, + array $params = [] + ): \Etsy\Collection { + return self::request( "GET", - "/application/listings/{$this->listing_id}/properties/{$property_id}", - "ListingProperty" + "/application/shops/{$shop_id}/listings/active", + "Listing", + $params + ); + } + + /** + * Get all featured listings for a shop. + * + * @param int $shop_id + * @param array $params + * @return \Etsy\Collection[Etsy\Resources\Listing] + */ + public static function allFeaturedByShop( + int $shop_id, + array $params = [] + ): \Etsy\Collection { + return self::request( + "GET", + "/application/shops/{$shop_id}/listings/featured", + "Listing", + $params ); - if($listing_property) { - $listing_property->shop_id = $this->shop_id; - $listing_property->listing_id = $this->listing_id; - } - return $listing_property; } /** - * Get the listing files associated with the listing. - * - * @link https://developers.etsy.com/documentation/reference#operation/getAllListingFiles - * @return Etsy\Collection[Etsy\Resources\ListingFile] + * Get all listings from a receipt. + * + * @param int $shop_id + * @param int $receipt_id + * @param array $params + * @return \Etsy\Collection[Etsy\Resources\Listing] */ - public function getFiles() { - return $this->request( + public static function allByReceipt( + int $shop_id, + int $receipt_id, + array $params = [] + ): \Etsy\Collection { + return self::request( "GET", - "/application/shops/{$this->shop_id}/listings/{$this->listing_id}/files", - "ListingFile" - ) - ->append(["shop_id" => $this->shop_id]); + "/application/shops/{$shop_id}/receipts/{$receipt_id}/listings", + "Listing", + $params + ); } /** - * Get a specific listing file. - * - * @link https://developers.etsy.com/documentation/reference#operation/getListingFile - * @param integer|string $listing_file_id - * @return Etsy\Resources\ListingFile + * Get all the listings within a shop return policy. + * + * @param int $shop_id + * @param int $policy_id + * @return \Etsy\Collection[\Etsy\Resources\Listing] */ - public function getFile($listing_file_id) { - $listing_file = $this->request( + public static function allByReturnPolicy( + int $shop_id, + int $policy_id + ): \Etsy\Collection { + return self::request( "GET", - "/application/shops/{$this->shop_id}/listings/{$this->listing_id}/files/{$listing_file_id}", - "ListingFile" + "/application/shops/{$shop_id}/policies/return/{$policy_id}/listings", + "Listing" ); - if($listing_file) { - $listing_file->shop_id = $this->shop_id; - } - return $listing_file; } /** - * Uploads a listing file. - * - * @link https://developers.etsy.com/documentation/reference#operation/uploadListingFile - * @param resource $file - * @param string $name - * @param integer|string $rank - * @return Etsy\Resources\ListingFile + * Get all listings withing specified shop sections. + * + * @param int $shop_id + * @param array|int $section_ids + * @param array $params + * @return \Etsy\Collection[\Etsy\Resources\Listing] */ - public function uploadFile( - $file, - string $name, - $rank = 1 - ) { - $data = [ - 'file' => $file, - 'name' => $name, - 'rank' => $rank - ]; - $listing_file = $this->request( + public static function allByShopSections( + int $shop_id, + array|int $section_ids, + array $params = [] + ): \Etsy\Collection { + $params['shop_section_ids'] = $section_ids; + return self::request( + "GET", + "/application/shops/{$shop_id}/shop-sections/listings", + "Listing", + $params + ); + } + + /** + * Get a listing. + * + * @param int $listing_id + * @param array $params + * @return \Etsy\Resources\Listing + */ + public static function get( + int $listing_id, + array $params = [] + ): ?\Etsy\Resources\Listing { + return self::request( + "GET", + "/application/listings/{$listing_id}", + "Listing", + $params + ); + } + + /** + * Create a draft Etsy listing. + * + * @param int $shop_id + * @param array $data + * @return \Etsy\Resources\Listing + */ + public static function create( + int $shop_id, + array $data + ): ?\Etsy\Resources\Listing { + return self::request( "POST", - "/application/shops/{$this->shop_id}/listings/{$this->listing_id}/files", - "ListingFile", + "/application/shops/{$shop_id}/listings", + "Listing", $data ); - if($listing_file) { - $listing_file->shop_id = $this->shop_id; - } - return $listing_file; } /** - * Links an existing file to the Listing. - * - * @link https://developers.etsy.com/documentation/reference#operation/uploadListingFile - * @param integer|string $listing_file_id - * @param integer|string $rank - * @return Etsy\Resources\ListingFile + * Delete an Etsy listing. + * + * @param int $listing_id + * @return bool */ - public function linkFile($listing_file_id, $rank = 1) { - $data = [ - 'listing_file_id' => $listing_file_id, - 'rank' => 1 - ]; - $listing_file = $this->request( - "POST", - "/application/shops/{$this->shop_id}/listings/{$this->listing_id}/files", - "ListingFile", + public static function delete( + int $listing_id + ): bool { + return self::deleteRequest( + "/application/listings/{$listing_id}" + ); + } + + /** + * Updates an Etsy listing. + * + * @param int $shop_id + * @param int $listing_id + * @param array $data + * @return \Etsy\Resources\Listing + */ + public static function update( + int $shop_id, + int $listing_id, + array $data + ): ?\Etsy\Resources\Listing { + return self::request( + "PATCH", + "/application/shops/{$shop_id}/listings/{$listing_id}", + "ListingProperty", $data ); - if($listing_file) { - $listing_file->shop_id = $this->shop_id; + } + + /** + * Saves updates to the current listing. + * + * @param array $data + * @return \Etsy\Resources\Listing + */ + public function save( + ?array $data = null + ): \Etsy\Resources\Listing { + if(!$data) { + $data = $this->getSaveData(true); } - return $listing_file; + if(count($data) == 0) { + return $this; + } + return $this->updateRequest( + "/application/shops/{$shop_id}/listings/{$listing_id}", + $data, + "PATCH" + ); } /** - * Get the Listing Images for the listing. - * - * @link https://developers.etsy.com/documentation/reference#operation/getListingImages - * @return Etsy\Collection[Etsy\Resources\ListingImage] + * Get all reviews for the listing. + * + * @param array $params + * @return \Etsy\Collection[Etsy\Resources\Review] */ - public function getImages() { - return $this->request( - "GET", - "/application/shops/{$this->shop_id}/listings/{$this->listing_id}/images", - "ListingImage" - ) - ->append(["shop_id" => $this->shop_id]); + public function reviews( + array $params = [] + ): \Etsy\Collection { + return Review::allByListing($this->listing_id, $params); } /** - * Get a specific listing image. - * - * @link https://developers.etsy.com/documentation/reference#operation/getListingImage - * @param integer|string $listing_image_id - * @return Etsy\Resources\ListingImage + * Get all transactions for the listing. + * + * @param array @params + * @return \Etsy\Collection[Etsy\Resources\Transaction] */ - public function getImage($listing_image_id) { - $listing_image = $this->request( - "GET", - "/application/shops/{$this->shop_id}/listings/{$this->listing_id}/images/{$listing_image_id}", - "ListingImage" + public function transactions( + array $params = [] + ): \Etsy\Collection { + return Transaction::allByListing($this->shop_id, $this->listing_id, $params); + } + + /** + * Get all properties for the listing. + * + * @return \Etsy\Collection[Etsy\Resources\ListingProperty] + */ + public function properties(): \Etsy\Collection { + return ListingProperty::all( + $this->shop_id, + $this->listing_id ); - if($listing_image) { - $listing_image->shop_id = $this->shop_id; - } - return $listing_image; } /** - * Upload a listing image. - * - * @link https://developers.etsy.com/documentation/reference#operation/uploadListingImage - * @param resource $file - * @param string $name - * @param integer|string $rank - * @param array $options - * @return Etsy\Resources\ListingImage + * Get all files for the listing. + * + * @return \Etsy\Collection[Etsy\Resources\ListingFile] */ - public function uploadImage( - $file, - string $name, - $rank = 1, - array $options - ) { - $data = array_merge($options, [ - 'file' => $file, - 'name' => $name, - 'rank' => $rank - ]); - $listing_image = $this->request( - "POST", - "/application/shops/{$this->shop_id}/listings/{$this->listing_id}/images", - "ListingImage", - $data + public function files(): \Etsy\Collection { + return ListingFile::all( + $this->shop_id, + $this->listing_id + ); + } + + /** + * Get a specific listing file. + * + * @param int $file_id + * @return \Etsy\Resources\ListingFile + */ + public function file( + int $file_id + ): ?\Etsy\Resources\ListingFile { + return ListingFile::get( + $this->shop_id, + $this->listing_id, + $file_id + ); + } + + /** + * Link a file to the listing. + * + * @param int $file_id + * @param int $rank + * @return \Etsy\Resources\ListingFile + */ + public function linkFile( + int $file_id, + int $rank = 1 + ): ?\Etsy\Resources\ListingFile { + return ListingFile::create( + $this->shop_id, + $this->listing_id, + [ + 'listing_file_id' => $file_id, + 'rank' => 1 + ] + ); + } + + /** + * Get the images for the listing. + * + * @return \Etsy\Collection[\Etsy\Resources\ListingImage] + */ + public function images(): \Etsy\Collection { + return ListingImage::all( + $this->listing_id + ); + } + + /** + * Get a specific listing image. + * + * @param int $image_id + * @return \Etsy\Resources\ListingImage + */ + public function image( + int $image_id + ): ?\Etsy\Resources\ListingImage { + return ListingImage::get( + $this->listing_id, + $image_id ); - if($listing_image) { - $listing_image->shop_id = $this->shop_id; - } - return $listing_image; } /** - * Links an existing image to the Listing. - * - * @link https://developers.etsy.com/documentation/reference#operation/uploadListingImage - * @param integer|string $listing_file_id - * @param integer|string $rank + * Link an existing image to the listing. + * + * @param int $image_id * @param array $options + * @return \Etsy\Resources\ListingImage */ public function linkImage( - $listing_image_id, - $rank = 1, - array $options = [] - ) { - // Attach the options. - $data = array_merge($options, [ - 'listing_image_id' => $listing_image_id, - 'rank' => $rank - ]); - $listing_image = $this->request( - "POST", - "/application/shops/{$this->shop_id}/listings/{$this->listing_id}/images", - "ListingImage", - $data + int $image_id, + $options = [] + ): ?\Etsy\Resources\ListingImage { + $options['listing_image_id'] = $image_id; + return ListingImage::create( + $this->shop_id, + $this->listing_id, + $options ); - if($listing_image) { - $listing_image->shop_id = $this->shop_id; - } - return $listing_image; } /** - * Update the inventory for the listing. - * - * @link https://developers.etsy.com/documentation/reference#operation/updateListingInventory - * @param array $data - * @return Etsy\Resources\ListingInventory + * Get the variation images for the listing. + * + * @return \Etsy\Collection[\Etsy\Resources\ListingVariationImage] */ - public function updateInventory(array $data) { - $inventory = $this->request( - "PUT", - "/application/listings/{$this->listing_id}/inventory", - "ListingInventory", - $data - ); - // Assign the listing ID to associated inventory products. - array_map( - (function($product){ - $product->listing_id = $this->listing_id; - }), - ($inventory->products ?? []) + public function variationImages(): \Etsy\Collection { + return ListingVariationImage::all( + $this->shop_id, + $this->listing_id ); - return $inventory; } /** - * Get a specific product for a listing. Use this method to bypass going through the ListingInventory resource. - * - * @link https://developers.etsy.com/documentation/reference#tag/ShopListing-Product - * @param integer|string $product_id - * @return Etsy\Resources\ListingProduct + * Get the videos for the listing. + * + * @return \Etsy\Collection[\Etsy\Resources\ListingVideo] */ - public function getProduct($product_id) { - $product = $this->request( - "GET", - "/application/listings/{$this->listing_id}/inventory/products/{$product_id}", - "ListingProduct" + public function videos(): \Etsy\Collection { + return ListingVideo::all( + $this->listing_id ); - if($product) { - $product->listing_id = $this->listing_id; - } - return $product; } /** - * Get a translation for the listing in a specific language. - * - * @link https://developers.etsy.com/documentation/reference#operation/getListingTranslation - * @param string $language - * @return Etsy\Resources\ListingTranslation + * Get a specific listing image. + * + * @param int $video_id + * @return \Etsy\Resources\ListingVideo */ - public function getTranslation( - string $language - ) { - $translation = $this->request( - "GET", - "/application/shops/{$this->shop_id}/listings/{$this->listing_id}/translations/{$language}", - "ListingTranslation" + public function video( + int $video_id + ): ?\Etsy\Resources\ListingVideo { + return ListingVideo::get( + $this->listing_id, + $video_id ); - if($translation) { - $translation->shop_id = $this->shop_id; - } - return $translation; } /** - * Creates a listing translation. - * - * @link https://developers.etsy.com/documentation/reference#operation/createListingTranslation - * @param string $language - * @param array $data - * @return Etsy\Resources\ListingTranslation + * Link an existing image to the listing. + * + * @param int $video_id + * @return \Etsy\Resources\ListingVideo */ - public function createTranslation( - string $language, - array $data - ) { - $translation = $this->request( - "POST", - "/application/shops/{$this->shop_id}/listings/{$this->listing_id}/translations/{$language}", - "ListingTranslation", + public function linkVideo( + int $video_id + ): ?\Etsy\Resources\ListingVideo { + $data['video_id'] = $video_id; + return ListingVideo::create( + $this->shop_id, + $this->listing_id, $data ); - if($translation) { - $translation->shop_id = $this->shop_id; - } - return $translation; } /** - * Gets variation images for the listing. - * - * @link https://developers.etsy.com/documentation/reference#operation/getListingVariationImages - * @return Etsy\Collection[Etsy\Resources\ListingVariationImage] + * Get the listing inventory. + * + * @return \Etsy\Resources\ListingInventory */ - public function getVariationImages() { - return $this->request( - "GET", - "/application/shops/{$this->shop_id}/listings/{$this->listing_id}/variation-images", - "ListingVariationImage" + public function inventory(): ?\Etsy\Resources\ListingInventory { + return ListingInventory::get( + $this->listing_id ); } /** - * Updates variation images for the listing. You MUST pass data for ALL variation images, including the ones you are not updating, as this method will override all existing variation images. - * - * @link https://developers.etsy.com/documentation/reference#operation/updateVariationImages - * @param array $data - * @return Etsy\Collection[Etsy\Resources\ListingVariationImage] + * Get a listing product. + * + * @param int $product_id + * @return \Etsy\Resources\ListingProduct */ - public function updateVariationImages(array $data) { - return $this->request( - "POST", - "/application/shops/{$this->shop_id}/listings/{$this->listing_id}/variation-images", - "ListingVariationImage", - $data + public function product( + int $product_id + ): ?\Etsy\Resources\ListingProduct { + return ListingProduct::get( + $this->listing_id, + $product_id ); } + /** + * Get a listing translation. + * + * @param string $language + * @return \Etsy\Resources\ListingTranslation + */ + public function translation( + string $language + ): ?\Etsy\Resources\ListingTranslation { + return ListingTranslation::get( + $this->shop_id, + $this->listing_id, + $language + ); + } + + } diff --git a/src/Resources/ListingFile.php b/src/Resources/ListingFile.php index 474a07b..d4e1160 100644 --- a/src/Resources/ListingFile.php +++ b/src/Resources/ListingFile.php @@ -13,14 +13,79 @@ class ListingFile extends Resource { /** - * Delete the listing file. + * Delete a listing file. * - * @link https://developers.etsy.com/documentation/reference#operation/deleteListingFile - * @return boolean + * @param int $shop_id + * @param int $listing_id + * @param int $file_id + * @return bool */ - public function delete() { - return $this->deleteRequest( - "/application/shops/{$this->shop_id}/listings/{$this->listing_id}/files/{$this->listing_file_id}" + public static function delete( + int $shop_id, + int $listing_id, + int $file_id + ): bool { + return self::deleteRequest( + "/application/shops/{$shop_id}/listings/{$listing_id}/files/{$file_id}" + ); + } + + /** + * Get a listing file. + * + * @param int $shop_id + * @param int $listing_id + * @param int $file_id + * @return \Etsy\Resources\ListingFile + */ + public static function get( + int $shop_id, + int $listing_id, + int $file_id + ): ?\Etsy\Resources\ListingFile { + return self::request( + "GET", + "/application/shops/{$shop_id}/listings/{$listing_id}/files/{$file_id}", + "ListingFile" + ); + } + + /** + * Get all files for a listing. + * + * @param int $shop_id + * @param int $listing_id + * @return \Etsy\Collection[\Etsy\Resources\ListingFile] + */ + public static function all( + int $shop_id, + int $listing_id + ): \Etsy\Collection { + return self::request( + "GET", + "/application/shops/{$shop_id}/listings/{$listing_id}/files", + "ListingFile" + ); + } + + /** + * Upload a listing file. + * + * @param int $shop_id + * @param int $listing_id + * @param array $data + * @return \Etsy\Resources\ListingFile + */ + public static function create( + int $shop_id, + int $listing_id, + array $data + ): ?\Etsy\Resources\ListingFile { + return self::request( + "POST", + "/application/shops/{$shop_id}/listings/{$listing_id}/files", + "ListingFile", + $data ); } } diff --git a/src/Resources/ListingImage.php b/src/Resources/ListingImage.php index fe6f415..1c73ed4 100644 --- a/src/Resources/ListingImage.php +++ b/src/Resources/ListingImage.php @@ -13,14 +13,75 @@ class ListingImage extends Resource { /** - * Delete the listing image. + * Get a listing image. + * + * @param int $listing_id + * @param int $image_id + * @return \Etsy\Resources\ListingImage + */ + public static function get( + int $listing_id, + int $image_id + ): ?\Etsy\Resources\ListingImage { + return self::request( + "GET", + "/application/listings/{$listing_id}/images/{$image_id}", + "ListingImage" + ); + } + + /** + * Get images for a listing. + * + * @param int $listing_id + * @return \Etsy\Collection[\Etsy\Resources\ListingImage] + */ + public static function all( + int $listing_id + ): \Etsy\Collection { + return self::request( + "GET", + "/application/listings/{$listing_id}/images", + "ListingImage" + ); + } + + /** + * Create a new image. + * + * @param int $shop_id + * @param int $listing_id + * @param array $data + * @return \Etsy\Resources\ListingImage + */ + public static function create( + int $shop_id, + int $listing_id, + array $data + ): ?\Etsy\Resources\ListingImage { + return self::request( + "POST", + "/application/shops/{$shop_id}/listings/{$listing_id}/images", + "ListingImage", + $data + ); + } + + /** + * Delete a listing image. * - * @link https://developers.etsy.com/documentation/reference#operation/deleteListingImage - * @return boolean + * @param int $shop_id + * @param int $listing_id + * @param int $image_id + * @return bool */ - public function delete() { - return $this->deleteRequest( - "/application/shops/{$this->shop_id}/listings/{$this->listing_id}/images/{$this->listing_image_id}" + public static function delete( + int $shop_id, + int $listing_id, + int $image_id + ): bool { + return self::deleteRequest( + "/application/shops/{$shop_id}/listings/{$listing_id}/images/{$image_id}" ); } } diff --git a/src/Resources/ListingInventory.php b/src/Resources/ListingInventory.php index 309119f..a754430 100644 --- a/src/Resources/ListingInventory.php +++ b/src/Resources/ListingInventory.php @@ -16,30 +16,72 @@ class ListingInventory extends Resource { * @var array */ protected $_associations = [ + "listing" => "Listing", "products" => "ListingProduct" ]; /** - * Update the Listing Inventory record. - * - * @link https://developers.etsy.com/documentation/reference/#operation/updateListingInventory + * Get the inventory for a listing. + * + * @param int $listing_id + * @param array @params + * @return \Etsy\Resources\ListingInventory + */ + public function get( + int $listing_id, + array $params = [] + ): ?\Etsy\Resources\ListingInventory { + $inventory = self::request( + "GET", + "/application/listings/{$listing_id}/inventory", + "ListingInventory", + $params + ); + if($inventory) { + $inventory->assignListingId($listing_id); + } + return $inventory; + } + + /** + * Update listing inventory. + * + * @param $listing_id * @param array $data - * @return Etsy\Resources\ListingInventory + * @return \Etsy\Resources\ListingInventory */ - public function update() { - // Don't use a regular resource update request here. - $inventory = $this->updateRequest( - "/application/listings/{$this->listing_id}/inventory", + public static function update( + int $listing_id, + array $data + ): ?\Etsy\Resources\ListingInventory { + $inventory = self::request( + "PUT", + "/application/listings/{$listing_id}/inventory", + "ListingInventory", $data ); - // Assign the listing ID to associated inventory products. + if($inventory) { + $inventory->assignListingId($listing_id); + } + return $inventory; + } + + /** + * Asssigns the listing ID to the inventory resource. + * + * @param int $listing_id + * @return void + */ + private function assignListingId( + int $listing_id + ) { + $this->listing_id = $listing_id; array_map( - (function($product){ - $product->listing_id = $this->listing_id; + (function($product) use($listing_id) { + $product->listing_id = $listing_id; }), ($inventory->products ?? []) ); - return $this; } } diff --git a/src/Resources/ListingOffering.php b/src/Resources/ListingOffering.php index 40ec00e..d3f87f3 100644 --- a/src/Resources/ListingOffering.php +++ b/src/Resources/ListingOffering.php @@ -10,4 +10,25 @@ * @link https://developers.etsy.com/documentation/reference#tag/ShopListing-Offering * @author Rhys Hall hello@rhyshall.com */ -class ListingOffering extends Resource {} +class ListingOffering extends Resource { + + /** + * Get a product offering. + * + * @param int $listing_id + * @param int $product_id + * @param int $offering_id + * @return \Etsy\Resources\ListingOffering + */ + public static function get( + int $listing_id, + int $product_id, + int $offering_id + ): ?\Etsy\Resources\ListingOffering { + return self::request( + "GET", + "/application/listings/{$listing_id}/products/{$product_id}/offerings/{$offering_id}", + "ListingOffering" + ); + } +} diff --git a/src/Resources/ListingProduct.php b/src/Resources/ListingProduct.php index da52cce..5c20d18 100644 --- a/src/Resources/ListingProduct.php +++ b/src/Resources/ListingProduct.php @@ -20,17 +20,40 @@ class ListingProduct extends Resource { ]; /** - * Get a specific offering from the product. - * - * @link https://developers.etsy.com/documentation/reference#operation/getListingOffering - * @param integer|string $product_offering_id - * @return Etsy\Resources\ListingOffering + * Get a listing product. + * + * @param int $listing_id + * @param int $product_id + * @return \Etsy\Resources\ListingProduct */ - public function getOffering($product_offering_id) { - return $this->request( + public static function get( + int $listing_id, + int $product_id + ): ?\Etsy\Resources\ListingProduct { + $product = self::request( "GET", - "/application/listings/{$this->listing_id}/products/{$this->product_id}/offerings/{$product_offering_id}", - "ListingOffering" + "/application/listings/{$listing_id}/inventory/products/{$product_id}", + "ListingProduct" + ); + if($product) { + $product->listing_id = $listing_id; + } + return $product; + } + + /** + * Get a specific listing offering. + * + * @param int $offering_id + * @return \Etsy\Resources\ListingOffering + */ + public function offering( + int $offering_id + ): ?\Etsy\Resources\ListingOffering { + return ListingOffering::get( + $this->listing_id, + $this->product_id, + $offering_id ); } diff --git a/src/Resources/ListingProperty.php b/src/Resources/ListingProperty.php index 7cab1e1..ede5193 100644 --- a/src/Resources/ListingProperty.php +++ b/src/Resources/ListingProperty.php @@ -13,28 +13,99 @@ class ListingProperty extends Resource { /** - * Updates the listing property. - * - * https://developers.etsy.com/documentation/reference#operation/updateListingProperty + * @var array + */ + protected $_saveable = [ + 'value_ids', + 'values', + 'scale_id' + ]; + + /** + * Get all properties for a listing. + * + * @param int $shop_id + * @param int $listing_id + * @return Etsy\Collection[Etsy\Resources\ListingProperty] + */ + public static function all( + int $shop_id, + int $listing_id + ): \Etsy\Collection { + return self::request( + "GET", + "/application/shops/{$shop_id}/listings/{$listing_id}/properties", + "ListingProperty" + )->append([ + 'shop_id' => $shop_id, + 'listing_id' => $listing_id + ]); + } + + /** + * Updates a listing property. + * + * @param int $shop_id + * @param int $listing_id + * @param int $property_id * @param array $data * @return Etsy\Resources\ListingProperty */ - public function update(array $data) { + public static function update( + int $shop_id, + int $listing_id, + int $property_id, + $data + ): ?\Etsy\Resources\ListingProperty { + $property = self::request( + "PUT", + "/application/shops/{$shop_id}/listings/{$listing_id}/properties/{$property_id}", + "ListingProperty", + $data + ); + if($property) { + $property->shop_id = $shop_id; + $property->listing_id = $listing_id; + } + return $property; + } + + /** + * Saves updates to the current listing property. + * + * @param array $data + * @return \Etsy\Resources\ListingProperty + */ + public function save( + ?array $data = null + ): \Etsy\Resources\ListingProperty { + if(!$data) { + $data = $this->getSaveData(); + } + if(count($data) == 0) { + return $this; + } return $this->updateRequest( - "/application/shops/{$this->shop_id}/listings/{$this->listing_id}/property/{$this->property_id}", + "/application/shops/{$this->shop_id}/listings/{$this->listing_id}/properties/{$this->property_id}", $data ); } /** - * Delete the listing property. - * - * @link https://developers.etsy.com/documentation/reference#operation/deleteListingProperty - * @return boolean + * Delete a listing property. + * + * @param int $shop_id + * @param int $listing_id + * @param int $property_id + * @return bool */ - public function delete() { - return $this->deleteRequest( - "/application/shops/{$this->shop_id}/listings/{$this->listing_id}/property/{$this->property_id}" + public static function delete( + int $shop_id, + int $listing_id, + int $property_id + ): bool { + return self::deleteRequest( + "/application/shops/{$shop_id}/listings/{$listing_id}/properties/{$property_id}" ); } } diff --git a/src/Resources/ListingTranslation.php b/src/Resources/ListingTranslation.php index 65ce865..0627d9a 100644 --- a/src/Resources/ListingTranslation.php +++ b/src/Resources/ListingTranslation.php @@ -13,13 +13,98 @@ class ListingTranslation extends Resource { /** - * Updates the listing translation. - * - * @link https://developers.etsy.com/documentation/reference#operation/updateListingTranslation + * Get a listing translation. + * + * @param int $shop_id + * @param int $listing_id + * @param string $language + * @return \Etsy\Resources\ListingTranslation + */ + public static function get( + int $shop_id, + int $listing_id, + string $language + ): ?\Etsy\Resources\ListingTranslation { + $translation = self::request( + "GET", + "/application/shops/{$shop_id}/listings/{$listing_id}/translations/{$language}", + "ListingTranslation" + ); + if($translation) { + $translation->shop_id = $shop_id; + } + return $translation; + } + + /** + * Create a listing translation. + * + * @param int $shop_id + * @param int $listing_id + * @param string $language + * @param array $data + * @return \Etsy\Resources\ListingTranslation + */ + public static function create( + int $shop_id, + int $listing_id, + string $language, + array $data + ): ?\Etsy\Resources\ListingTranslation { + $translation = self::request( + "POST", + "/application/shops/{$shop_id}/listings/{$listing_id}/translations/{$language}", + "ListingTranslation", + $data + ); + if($translation) { + $translation->shop_id = $shop_id; + } + return $translation; + } + + /** + * Update a listing translation. + * + * @param int $shop_id + * @param int $listing_id + * @param string $language + * @param array $data + * @return \Etsy\Resources\ListingTranslation + */ + public static function update( + int $shop_id, + int $listing_id, + string $language, + array $data + ): ?\Etsy\Resources\ListingTranslation { + $translation = self::request( + "PUT", + "/application/shops/{$shop_id}/listings/{$listing_id}/translations/{$language}", + "ListingTranslation", + $data + ); + if($translation) { + $translation->shop_id = $shop_id; + } + return $translation; + } + + /** + * Save updates to the current translation. + * * @param array $data - * @return Etsy\Resources\ListingTranslation + * @return \Etsy\Resources\ListingTranslation */ - public function update(array $data) { + public function save( + ?array $data = nul + ): \Etsy\Resources\ListingTranslation { + if(!$data) { + $data = $this->getSaveData(); + } + if(count($data) == 0) { + return $this; + } return $this->updateRequest( "/application/shops/{$this->shop_id}/listings/{$this->listing_id}/translations/{$this->language}", $data diff --git a/src/Resources/ListingVariationImage.php b/src/Resources/ListingVariationImage.php index 5a4fc67..bcaba26 100644 --- a/src/Resources/ListingVariationImage.php +++ b/src/Resources/ListingVariationImage.php @@ -10,4 +10,46 @@ * @link https://developers.etsy.com/documentation/reference#tag/ShopListing-VariationImage * @author Rhys Hall hello@rhyshall.com */ -class ListingVariationImage extends Resource {} +class ListingVariationImage extends Resource { + + /** + * Get variation images for a listing. + * + * @param int $shop_id + * @param int $listing_id + * @return \Etsy\Collection[\Etsy\Resources\ListingVariationImage] + */ + public static function all( + int $shop_id, + int $listing_id + ): \Etsy\Collection { + return self::request( + "GET", + "/application/shops/{$shop_id}/listings/{$listing_id}/variation-images", + "ListingVariationImage" + ); + } + + /** + * Update variation images for a listing. + * + * @param int $shop_id + * @param $listing_id + * @param array $variation_images + * @return \Etsy\Resources\ListingVariationImage + */ + public static function update( + int $shop_id, + int $listing_id, + array $variation_images + ): ?\Etsy\Resources\ListingVariationImage { + return self::request( + "POST", + "/application/shops/{$shop_id}/listings/{$listing_id}/variation-images", + "ListingVariationImage", + [ + 'variation_images' => $variation_images + ] + ); + } +} diff --git a/src/Resources/ListingVideo.php b/src/Resources/ListingVideo.php new file mode 100644 index 0000000..ba48f06 --- /dev/null +++ b/src/Resources/ListingVideo.php @@ -0,0 +1,88 @@ + $payment_ids + ] + ); + } + + /** + * Get all payments for a specific receipt. + * + * @param int $shop_id + * @param int $receipt_id + * @return Etsy\Collection[Etsy\Resources\Payment] + */ + public static function allByReceipt( + int $shop_id, + int $receipt_id + ): \Etsy\Collection { + return self::request( + "GET", + "/application/shops/{$shop_id}/receipts/{$receipt_id}/payments", + "Payment" + ); + } + + /** + * Get payments for one or more ledger entries. + * + * @param int $shop_id + * @param int|array $ledger_entry_ids + * @return Etsy\Collection[Etsy\Resources\Payment] + */ + public static function allByLedgerEntries( + int $shop_id, + int|array $ledger_entry_ids + ): \Etsy\Collection { + return self::request( + "GET", + "/application/shops/{$shop_id}/payment-account/ledger-entries/payments", + "Payment", + [ + 'ledger_entry_ids' => $ledger_entry_ids + ] + ); + } + +} diff --git a/src/Resources/ProductionPartner.php b/src/Resources/ProductionPartner.php new file mode 100644 index 0000000..4bfcfe7 --- /dev/null +++ b/src/Resources/ProductionPartner.php @@ -0,0 +1,31 @@ +append(['shop_id' => $shop_id]); + } + + /** + * Get a single receipt. + * + * @param int $shop_id + * @param int $receipt_id + * @return \Etsy\Resources\Receipt + */ + public static function get( + int $shop_id, + int $receipt_id + ): ?\Etsy\Resources\Receipt { + $receipt = self::request( + "GET", + "/application/shops/{$shop_id}/receipts/{$receipt_id}", + "Receipt" + ); + if($receipt) { + $receipt->shop_id = $shop_id; + } + return $receipt; + } + + /** + * Update a shop receipt. + * + * @param int $shop_id + * @param int $receipt_id * @param array $data - * @return Etsy\Resources\Shipment + * @return Etsy\Resources\Receipt */ - public function createShipment(array $data) { - $shipment = $this->request( - "POST", - "/application/shops/{$this->shop_id}/receipts/{$this->receipt_id}/tracking", - "Shipment", + public static function update( + int $shop_id, + int $receipt_id, + array $data + ): ?\Etsy\Resources\Receipt { + $receipt = self::request( + "PUT", + "/application/shops/{$shop_id}/receipts/{$receipt_id}", + "Receipt", $data ); - // Add the shipment to the associated property. - $this->_properties->shipments[] = $shipment; - return $shipment; + if($receipt) { + $receipt->shop_id = $shop_id; + } + return $receipt; } /** - * Gets all transactions for the receipt. + * Saves updates to the current section. * - * @link https://developers.etsy.com/documentation/reference#operation/getShopReceiptTransactionsByReceipt - * @return Etsy\Collection[Etsy\Resources\Transaction] + * @param array $data + * @return Etsy\Resources\Receipt */ - public function getTransactions() { - return $this->request( - "GET", - "/application/shops/{$this->shop_id}/receipts/{$this->receipt_id}/transactions", - "Transaction" + public function save( + ?array $data = null + ): \Etsy\Resources\Receipt { + if(!$data) { + $data = $this->getSaveData(); + } + if(count($data) == 0) { + return $this; + } + return $this->updateRequest( + "/application/shops/{$this->shop_id}/receipts/{$this->receipt_id}", + $data ); } /** - * Gets all payments for the receipt. - * - * @link https://developers.etsy.com/documentation/reference#operation/getShopPaymentByReceiptId - * @return Etsy\Collection[Etsy\Resources\Payment] + * Get all transactions for the receipt. + * + * @return \Etsy\Collection[\Etsy\Resources\Transaction] */ - public function getPayments() { - return $this->request( - "GET", - "/application/shops/{$this->shop_id}/receipts/{$this->receipt_id}/payments", - "Payment" - ); + public function transactions(): \Etsy\Collection { + return Transaction::allByReceipt($this->shop_id, $this->receipt_id); } /** - * Get all listings associated with the receipt. - * - * @link https://developers.etsy.com/documentation/reference#operation/getListingsByShopReceipt - * @param array $params - * @return Etsy\Collection[Etsy\Resources\Listing] + * Get all payments for the receipt. + * + * @return \Etsy\Collections[\Etsy\Resources\Payment] */ - public function getListings($params = []) { - return $this->request( - "GET", - "/application/shops/{$this->shop_id}/receipts/{$this->receipt_id}/listings", - "Listing", + public function payments(): \Etsy\Collection { + return Payment::allByReceipt($this->shop_id, $this->receipt_id); + } + + /** + * Get all listings for the receipt. + * + * @param array @params + * @return \Etsy\Collections[\Etsy\Resources\Listing] + */ + public function listings( + array $params = [] + ): \Etsy\Collection { + return Listing::allByReceipt( + $this->shop_id, + $this->receipt_id, $params ); } diff --git a/src/Resources/ReturnPolicy.php b/src/Resources/ReturnPolicy.php new file mode 100644 index 0000000..5a7ee8f --- /dev/null +++ b/src/Resources/ReturnPolicy.php @@ -0,0 +1,165 @@ +getSaveData(); + } + if(count($data) == 0) { + return $this; + } + return $this->updateRequest( + "/application/shops/{$this->shop_id}/policies/return/{$this->return_policy_id}", + $data + ); + } + + /** + * Get all listings associated with this policy. + * + * @return \Etsy\Collection[\Etsy\Resources\Listing] + */ + public function listings(): \Etsy\Collection { + return Listing::allByReturnPolicy( + $this->shop_id, + $this->return_policy_id + ); + } + +} diff --git a/src/Resources/Review.php b/src/Resources/Review.php index 1cd75fb..1aa4178 100644 --- a/src/Resources/Review.php +++ b/src/Resources/Review.php @@ -10,4 +10,43 @@ * @link https://developers.etsy.com/documentation/reference/#tag/Review * @author Rhys Hall hello@rhyshall.com */ -class Review extends Resource {} +class Review extends Resource { + + /** + * Get all Shop reviews. + * + * @param int $shop_id + * @param array $params + * @return \Etsy\Collection[\Etsy\Resources\Review] + */ + public static function all( + int $shop_id, + array $params = [] + ): \Etsy\Collection { + return self::request( + "GET", + "/application/shops/{$shop_id}/reviews", + "Review", + $params + ); + } + + /** + * Get all listing reviews. + * + * @param int $listing_id + * @param array $params + * @return \Etsy\Collection[\Etsy\Resources\Review] + */ + public static function allByListing( + int $listing_id, + array $params = [] + ): \Etsy\Collection { + return self::request( + "GET", + "/application/listings/{$listing_id}/reviews", + "Review", + $params + ); + } +} diff --git a/src/Resources/SellerTaxonomy.php b/src/Resources/SellerTaxonomy.php new file mode 100644 index 0000000..3bbf905 --- /dev/null +++ b/src/Resources/SellerTaxonomy.php @@ -0,0 +1,28 @@ + $iso_code + ] + ); + } +} diff --git a/src/Resources/ShippingDestination.php b/src/Resources/ShippingDestination.php index 0dc4f32..460fb2d 100644 --- a/src/Resources/ShippingDestination.php +++ b/src/Resources/ShippingDestination.php @@ -12,29 +12,127 @@ */ class ShippingDestination extends Resource { + protected $_saveable = [ + 'primary_cost', + 'secondary_cost', + 'destination_country_iso', + 'destination_region', + 'shipping_carrier_id', + 'mail_class', + 'min_delivery_days', + 'max_delivery_days' + ]; + /** - * Updates the shipping profile. - * - * @link https://developers.etsy.com/documentation/reference#operation/updateShopShippingProfileDestination + * Get all shipping destinations for a profile. + * + * @param int $shop_id + * @param int $profile_id + * @param array $params + * @return Etsy\Collection[Etsy\Resources\ShippingDestination] + */ + public static function all( + int $shop_id, + int $profile_id, + array $params = [] + ): \Etsy\Collection { + return self::request( + "GET", + "/application/shops/{$shop_id}/shipping-profiles/{$profile_id}/destinations", + "ShippingDestination", + $params + )->append(['shop_id' => $shop_id]); + } + + /** + * Create a new shipping profile destination. + * + * @param int $shop_id + * @param int $profile_id * @param array $data * @return Etsy\Resources\ShippingDestination */ - public function update(array $data) { - return $this->updateRequest( - "/application/shops/{$this->shop_id}/shipping-profiles/{$this->shipping_profile_id}/destinations/{$this->shipping_profile_destination_id}", + public static function create( + int $shop_id, + int $profile_id, + array $data + ): ?\Etsy\Resources\ShippingDestination { + $destination = self::request( + "POST", + "/application/shops/{$shop_id}/shipping-profiles/{$profile_id}/destinations", + "ShippingDestination", $data ); + if($destination) { + $destination->shop_id = $shop_id; + } + return $destination; } /** - * Delete the shipping profile. + * Update a shipping profile destination. + * + * @param int $shop_id + * @param int $profile_id + * @param int $destination_id + * @param array $data + * @return Etsy\Resources\ShippingDestination + */ + public static function update( + int $shop_id, + int $profile_id, + int $destination_id, + array $data + ): ?\Etsy\Resources\ShippingDestination { + $destination = self::request( + "PUT", + "/application/shops/{$shop_id}/shipping-profiles/{$profile_id}/destinations/{$destination_id}", + "ShippingDestination", + $data + ); + if($destination) { + $destination->shop_id = $shop_id; + } + return $destination; + } + + /** + * Deletes a shipping profile destination. + * + * @param int $shop_id + * @param int $profile_id + * @param int $destination_id + * @return bool + */ + public static function delete( + int $shop_id, + int $profile_id, + int $destination_id + ): bool { + return self::deleteRequest( + "/application/shops/{$shop_id}/shipping-profiles/{$profile_id}/destinations/{$destination_id}", + ); + } + + /** + * Saves updates to the current shipping profile destination. * - * @link https://developers.etsy.com/documentation/reference#operation/deleteShopShippingProfileDestination - * @return boolean + * @param array $data + * @return Etsy\Resources\ShippingDestination */ - public function delete() { - return $this->deleteRequest( - "/application/shops/{$this->shop_id}/shipping-profiles/{$this->shipping_profile_id}/destinations/{$this->shipping_profile_destination_id}" + public function save( + ?array $data = null + ): \Etsy\Resources\ShippingDestination { + if(!$data) { + $data = $this->getSaveData(); + } + if(count($data) == 0) { + return $this; + } + return $this->updateRequest( + "/application/shops/{$this->shop_id}/shipping-profiles/{$this->shipping_profile_id}/destinations/{$this->shipping_profile_destination_id}", + $data ); } + } diff --git a/src/Resources/ShippingProfile.php b/src/Resources/ShippingProfile.php index 7a660eb..994e02d 100644 --- a/src/Resources/ShippingProfile.php +++ b/src/Resources/ShippingProfile.php @@ -21,71 +21,202 @@ class ShippingProfile extends Resource { ]; /** - * Updates the shipping profile. - * - * @link https://developers.etsy.com/documentation/reference/#operation/updateShopShippingProfile - * @param array $data - * @return Etsy\Resources\ShippingProfile + * @var array */ - public function update(array $data) { - return $this->updateRequest( - "/application/shops/{$this->shop_id}/shipping-profiles/{$this->shipping_profile_id}", - $data + protected $_saveable = [ + 'title', + 'origin_country_iso', + 'min_processing_time', + 'max_processing_time', + 'processing_time_unit', + 'origin_postal_code' + ]; + + + /** + * Get all shipping profiles for a shop. + * + * @param int $shop_id + * @return Etsy\Collection[Etsy\Resources\ShippingProfile] + */ + public static function all( + int $shop_id + ): \Etsy\Collection { + $profiles = self::request( + "GET", + "/application/shops/{$shop_id}/shipping-profiles", + "ShippingProfile" + ); + array_map( + (function($profile) use($shop_id) { + $profile->assignShopIdToProfile($shop_id); + }), + $profiles->data ); + return $profiles; } /** - * Delete the shipping profile. - * - * @link https://developers.etsy.com/documentation/reference/#operation/deleteShopShippingProfile - * @return boolean + * Get a specifc shipping profile. + * + * @param int $shop_id + * @param int $profile_id + * @return Etsy\Resources\ShippingProfile */ - public function delete() { - return $this->deleteRequest( - "/application/shops/{$this->shop_id}/shipping-profiles/{$this->shipping_profile_id}" + public static function get( + int $shop_id, + int $profile_id + ): ?\Etsy\Resources\ShippingProfile { + $profile = self::request( + "GET", + "/application/shops/{$shop_id}/shipping-profiles/{$profile_id}", + "ShippingProfile" ); + if($profile) { + $profile->assignShopIdToProfile($shop_id); + } + return $profile; } /** - * Creates a new shipping destination. - * - * @link https://developers.etsy.com/documentation/reference#operation/createShopShippingProfileDestination + * Create a new shipping profile. + * + * @param int $shop_id * @param array $data - * @return Etsy\Resources\ShippingDestination + * @return Etsy\Resources\ShippingProfile */ - public function createShippingDestination($data) { - $destination = $this->request( + public static function create( + int $shop_id, + array $data + ): ?\Etsy\Resources\ShippingProfile { + $profile = self::request( "POST", - "/application/shops/{$this->shop_id}/shipping-profiles/{$this->shipping_profile_id}/destinations", - "ShippingDestination", + "/application/shops/{$shop_id}/shipping-profiles", + "ShippingProfile", + $data + ); + if($profile) { + $profile->assignShopIdToProfile($shop_id); + } + return $profile; + } + + /** + * Update a shipping profile. + * + * @param int $shop_id + * @param int $profile_id + * @param array $data + * @return Etsy\Resources\ShippingProfile + */ + public static function update( + int $shop_id, + int $profile_id, + array $data + ): ?\Etsy\Resources\ShippingProfile { + $profile = self::request( + "PUT", + "/application/shops/{$shop_id}/shipping-profiles/{$profile_id}", + "ShippingProfile", $data ); - // Add the shop ID property to the destination. - $destination->shop_id = $this->shop_id; - // Add the new shipping destination to the associated property. - $this->_properties->shipping_profile_destinations[] = $destination; - return $destination; + if($profile) { + $profile->assignShopIdToProfile($shop_id); + } + return $profile; } /** - * Creates a new shipping upgrade. + * Deletes a shipping profile. + * + * @param int $shop_id + * @param int $profile_id + * @return bool + */ + public static function delete( + int $shop_id, + int $profile_id + ): bool { + return self::deleteRequest( + "/application/shops/{$shop_id}/shipping-profiles/{$profile_id}", + ); + } + + /** + * Saves updates to the current shipping profile. * - * @link https://developers.etsy.com/documentation/reference#operation/createShopShippingProfileUpgrade * @param array $data - * @return Etsy\Resources\ShippingUpgrade + * @return Etsy\Resources\ShippingProfile */ - public function createShippingUpgrade($data) { - $upgrade = $this->request( - "POST", - "/application/shops/{$this->shop_id}/shipping-profiles/{$this->shipping_profile_id}/upgrades", - "ShippingUpgrade", + public function save( + ?array $data = null + ): \Etsy\Resources\ShippingProfile { + if(!$data) { + $data = $this->getSaveData(); + } + if(count($data) == 0) { + return $this; + } + return $this->updateRequest( + "/application/shops/{$this->shop_id}/shipping-profiles/{$this->shipping_profile_id}", $data ); - // Add the shop ID property to the destination. - $upgrade->shop_id = $this->shop_id; - // Add the new shipping upgrade to the associated property. - $this->_properties->shipping_profile_upgrades[] = $upgrade; - return $upgrade; + } + + /** + * Get the shipping destinations for this profile. + * + * @param array $params + * @return \Etsy\Collection[Etsy\Resources\ShippingDestination] + */ + public function destinations( + array $params = [] + ): \Etsy\Collection { + $destinations = ShippingDestination::all( + $this->shop_id, + $this->shipping_profile_id, + $params + ); + $this->shipping_profile_destinations = $destinations; + return $destinations; + } + + /** + * Get the shipping upgrades for this profile. + * + * @return \Etsy\Collection[Etsy\Resources\ShippingUpgrade] + */ + public function upgrades(): \Etsy\Collection { + $upgrades = ShippingUpgrade::all( + $this->shop_id, + $this->shipping_profile_id + ); + $this->shipping_profile_upgrades = $upgrades; + return $upgrades; + } + + /** + * Assigns the shop ID property to the profile and associations. + * + * @param int $shop_id + * @return void + */ + private function assignShopIdToProfile( + int $shop_id + ) { + $this->shop_id = $shop_id; + array_map( + (function($destination) { + $destination->shop_id = $this->shop_id; + }), + ($this->shipping_profile_destinations ?? []) + ); + array_map( + (function($upgrade) { + $upgrade->shop_id = $this->shop_id; + }), + ($this->shipping_profile_upgrades ?? []) + ); } } diff --git a/src/Resources/ShippingUpgrade.php b/src/Resources/ShippingUpgrade.php index bb3a7a2..27ae04a 100644 --- a/src/Resources/ShippingUpgrade.php +++ b/src/Resources/ShippingUpgrade.php @@ -12,29 +12,124 @@ */ class ShippingUpgrade extends Resource { + protected $_saveable = [ + 'upgrade_name', + 'type', + 'price', + 'destination_region', + 'secondary_price', + 'shipping_carrier_id', + 'mail_class', + 'min_delivery_days', + 'max_delivery_days' + ]; + /** - * Updates the shipping profile. - * - * @link https://developers.etsy.com/documentation/reference#operation/updateShopShippingProfileUpgrade + * Get all shipping upgrades for a profile. + * + * @param int $shop_id + * @param int $profile_id + * @return Etsy\Collection[Etsy\Resources\ShippingUpgrade] + */ + public static function all( + int $shop_id, + int $profile_id + ): \Etsy\Collection { + return self::request( + "GET", + "/application/shops/{$shop_id}/shipping-profiles/{$profile_id}/upgrades", + "ShippingUpgrade" + )->append(['shop_id' => $shop_id]); + } + + /** + * Create a new shipping profile upgrade. + * + * @param int $shop_id + * @param int $profile_id * @param array $data * @return Etsy\Resources\ShippingUpgrade */ - public function update(array $data) { - return $this->updateRequest( - "/application/shops/{$this->shop_id}/shipping-profiles/{$this->shipping_profile_id}/upgrades/{$this->upgrade_id}", + public static function create( + int $shop_id, + int $profile_id, + array $data + ): ?\Etsy\Resources\ShippingUpgrade { + $upgrade = self::request( + "POST", + "/application/shops/{$shop_id}/shipping-profiles/{$profile_id}/upgrades", + "ShippingUpgrade", $data ); + if($upgrade) { + $upgrade->shop_id = $shop_id; + } + return $upgrade; } /** - * Delete the shipping profile. + * Update a shipping profile upgrade. + * + * @param int $shop_id + * @param int $profile_id + * @param int $upgrade_id + * @param array $data + * @return Etsy\Resources\ShippingUpgrade + */ + public static function update( + int $shop_id, + int $profile_id, + int $upgrade_id, + array $data + ): ?\Etsy\Resources\ShippingUpgrade { + $upgrade = self::request( + "PUT", + "/application/shops/{$shop_id}/shipping-profiles/{$profile_id}/upgrades/{$upgrade_id}", + "ShippingUpgrade", + $data + ); + if($upgrade) { + $upgrade->shop_id = $shop_id; + } + return $upgrade; + } + + /** + * Deletes a shipping profile upgrade. + * + * @param int $shop_id + * @param int $profile_id + * @param int $upgrade_id + * @return bool + */ + public static function delete( + int $shop_id, + int $profile_id, + int $upgrade_id + ): bool { + return self::deleteRequest( + "/application/shops/{$shop_id}/shipping-profiles/{$profile_id}/upgrades/{$upgrade_id}", + ); + } + + /** + * Saves updates to the current shipping profile upgrade. * - * @link https://developers.etsy.com/documentation/reference#operation/deleteShopShippingProfileUpgrade - * @return boolean + * @param array $data + * @return Etsy\Resources\ShippingUpgrade */ - public function delete() { - return $this->deleteRequest( + public function save( + ?array $data = null + ): \Etsy\Resources\ShippingUpgrade { + if(!$data) { + $data = $this->getSaveData(); + } + if(count($data) == 0) { + return $this; + } + return $this->updateRequest( "/application/shops/{$this->shop_id}/shipping-profiles/{$this->shipping_profile_id}/upgrades/{$this->upgrade_id}", + $data ); } } diff --git a/src/Resources/Shop.php b/src/Resources/Shop.php index 114b9cb..7d481b2 100644 --- a/src/Resources/Shop.php +++ b/src/Resources/Shop.php @@ -3,8 +3,23 @@ namespace Etsy\Resources; use Etsy\Resource; -use Etsy\Exception\SdkException; use Etsy\Utils\Date; +use Etsy\Exception\{ + SdkException, + ApiException +}; +use Etsy\Resources\{ + Listing, + ProductionPartner, + ShopSection, + ReturnPolicy, + ShippingProfile, + Review, + Receipt, + LedgerEntry, + Payment, + Transaction +}; /** * Shop resource class. Represents a Etsy user's shop. @@ -13,353 +28,305 @@ * @author Rhys Hall hello@rhyshall.com */ class Shop extends Resource { + + /** + * @var array + */ + protected $_saveable = [ + 'title', + 'announcement', + 'sale_message', + 'digital_sale_message', + 'policy_additional' + ]; /** - * Update the shop. - * + * Gets an Etsy shop. + * + * @param int $shop_id + * @return ?Etsy\Resources\Shop + */ + public static function get( + int $shop_id + ): ?\Etsy\Resources\Shop { + return self::request( + "GET", + "/application/shops/{$shop_id}", + "Shop" + ); + } + + /** + * Updates a shop. + * + * @param int $shop_id * @param array $data - * @return Etsy\Resources\Shop + * @return ?Etsy\Resources\Shop */ - public function update(array $data) { - return $this->updateRequest( - "/application/shops/{$this->shop_id}", + public static function update( + int $shop_id, + array $data + ): ?\Etsy\Resources\Shop { + return self::request( + 'PUT', + "/application/shops/{$shop_id}", + "Shop", $data ); } /** - * Get all sections for the shop. - * + * Search for shops. + * + * @param string $keyword * @param array $params - * @return \Etsy\Collection + * @return Etsy\Collection[Etsy\Resources\Shop] */ - public function getSections($params = []) { - return $this->request( - "GET", - "/application/shops/{$this->shop_id}/sections", - "ShopSection", + public static function all( + string $keyword, + array $params = [] + ): \Etsy\Collection { + if(!strlen(trim($keyword))) { + throw new ApiException("You must specify a keyword when searching for Etsy shops."); + } + $params['shop_name'] = $keyword; + return self::request( + 'GET', + "/application/shops", + "Shop", $params - ) - ->append(['shop_id' => $this->shop_id]); + ); } /** - * Get a specific shop section. - * - * @param integer|string $section_id - * @return \Etsy\Resources\ShopSection + * Get a count of all shops. + * + * @param string $keyword + * @param array $params + * @return int */ - public function getSection($section_id) { - $section = $this->request( - "GET", - "/application/shops/{$this->shop_id}/sections/{$section_id}", - "ShopSection" - ); - if($section) { - $section->shop_id = $this->shop_id; + public static function count( + string $keyword, + array $params = [] + ): int { + $result = self::all($keyword, $params); + if(!$result || !isset($result->count)) { + return 0; } - return $section; + return $result->count; } /** - * Creates a new shop section. + * Saves updates to the current shop. * - * @param string $data - * @return \Etsy\Resources\ShopSection + * @param array $data + * @return Etsy\Resources\Shop */ - public function createSection(string $title) { - if(!strlen(trim($title))) { - throw new SdkException("Section title cannot be blank."); + public function save( + ?array $data = null + ): \Etsy\Resources\Shop { + if(!$data) { + $data = $this->getSaveData(); + } + if(count($data) == 0) { + return $this; } - return $this->request( - "POST", - "/application/shops/{$this->shop_id}/sections", - "ShopSection", - ["title" => $title] + return $this->updateRequest( + "/application/shops/{$this->shop_id}", + $data ); } /** - * Get all reviews for the shop. - * + * Get all listings for the shop. + * * @param array $params - * @return Etsy\Collection[Etsy\Resources\Review] + * @return Etsy\Collection[Etsy\Resources\Listing] */ - public function getReviews(array $params = []) { - return $this->request( - "GET", - "/application/shops/{$this->shop_id}/reviews", - "Review", - $params - ); + public function listings( + array $params = [] + ): \Etsy\Collection { + return Listing::allByShop($this->shop_id, $params); } /** - * Get all shipping profiles for the shop. - * - * @return Etsy\Collection[Etsy\Resources\ShippingProfile] + * Get all active listings for the shop. + * + * @param array $params + * @return Etsy\Collection[Etsy\Resources\Listing] */ - public function getShippingProfiles() { - $profiles = $this->request( - "GET", - "/application/shops/{$this->shop_id}/shipping-profiles", - "ShippingProfile" - ) - ->append(['shop_id' => $this->shop_id]); - // Assign the shop ID to associated resources. - array_map( - (function($profile){ - $this->assignShopIdToProfile($profile); - }), - $profiles->data - ); - return $profiles; + public function activeListings( + array $params = [] + ): \Etsy\Collection { + return Listing::allActiveByShop($this->shop_id, $params); } /** - * Gets a single shipping profile for the shop. - * - * @param integer|string $shipping_profile_id - * @return Etsy\Resources\ShippingProfile + * Get all featured listings for the shop. + * + * @param array $params + * @return Etsy\Collection[Etsy\Resources\Listing] */ - public function getShippingProfile($shipping_profile_id) { - $profile = $this->request( - "GET", - "/application/shops/{$this->shop_id}/shipping-profiles/{$shipping_profile_id}", - "ShippingProfile" - ); - // Assign the shop id to the profile and associated resources. - $this->assignShopIdToProfile($profile); - return $profile; + public function featuedListings( + array $params = [] + ): \Etsy\Collection { + return Listing::allFeaturedByShop($this->shop_id, $params); } /** - * Creates a new shipping profile for the shop. - * - * @link https://developers.etsy.com/documentation/reference/#operation/createShopShippingProfile - * @param array $data - * @return Etsy\Resources\ShippingProfile + * Get all production partners for the shop. + * + * @return Etsy\Collection[Etsy\Resources\ProductionPartner] */ - public function createShippingProfile(array $data) { - $profile = $this->request( - "POST", - "/application/shops/{$this->shop_id}/shipping-profiles", - "ShippingProfile", - $data - ); - // Assign the shop id to the profile and associated resources. - $this->assignShopIdToProfile($profile); - return $profile; + public function productionPartners(): \Etsy\Collection { + return ProductionPartner::all($this->shop_id); } /** - * Assigns the shop ID to a shipping profile. - * - * @param Etsy\Resources\ShippingProfile $profile - * @return void + * Get all sections for the shop. + * + * @return Etsy\Collection[Etsy\Resources\ShopSection] */ - private function assignShopIdToProfile( - \Etsy\Resources\ShippingProfile $profile - ) { - $profile->shop_id = $this->shop_id; - array_map( - (function($destination) { - $destination->shop_id = $this->shop_id; - }), - ($profile->shipping_profile_destinations ?? []) - ); - array_map( - (function($upgrade) { - $upgrade->shop_id = $this->shop_id; - }), - ($profile->shipping_profile_upgrades ?? []) - ); + public function sections(): \Etsy\Collection { + return ShopSection::all($this->shop_id); } /** - * Get all receipts for the shop. - * - * @param array $params - * @return Etsy\Collection[Etsy\Resources\Receipt] + * Get a specific section within the shop. + * + * @param int $section_id + * @return Etsy\Resources\ShopSection */ - public function getReceipts(array $params = []) { - return $this->request( - "GET", - "/application/shops/{$this->shop_id}/receipts", - "Receipt", - $params - ) - ->append(['shop_id' => $this->shop_id]); + public function section( + int $section_id + ): ?ShopSection { + return ShopSection::get($this->shop_id, $section_id); } /** - * Gets a single receipt for the shop. - * - * @param integer|string $receipt_id - * @return Etsy\Resources\Receipt + * Get all return policies for the shop. + * + * @return Etsy\Collection[Etsy\Resources\ReturnPolicy] */ - public function getReceipt($receipt_id) { - $receipt = $this->request( - "GET", - "/application/shops/{$this->shop_id}/receipts/{$receipt_id}", - "Receipt" - ); - if($receipt) { - $receipt->shop_id = $this->shop_id; - } - return $receipt; + public function returnPolicies(): \Etsy\Collection { + return ReturnPolicy::all($this->shop_id); } /** - * Get all transactions for the shop. - * - * @link https://developers.etsy.com/documentation/reference#operation/getShopReceiptTransactionsByShop - * @param array $params - * @return Etsy\Collection[Etsy\Resources\Transaction] + * Get a specific return policy within the shop. + * + * @param int $policy_id + * @return Etsy\Resources\ReturnPolicy */ - public function getTransactions(array $params = []) { - return $this->request( - "GET", - "/application/shops/{$this->shop_id}/transactions", - "Transaction", - $params - ); + public function returnPolicy( + int $policy_id + ): ?ReturnPolicy { + return ReturnPolicy::get($this->shop_id, $policy_id); } /** - * Get a specific transaction for the shop. - * - * @link https://developers.etsy.com/documentation/reference#operation/getShopReceiptTransaction - * @param integer|string $transaction_id - * @return Etsy\Resources\Transaction + * Get all shipping profiles for the shop. + * + * @return Etsy\Collection[Etsy\Resources\ShippingProfile] */ - public function getTransaction($transaction_id) { - return $this->request( - "GET", - "/application/shops/{$this->shop_id}/transactions/{$transaction_id}", - "Transaction" - ); + public function shippingProfiles(): \Etsy\Collection { + return ShippingProfile::all($this->shop_id); } /** - * Get all payment account ledger entries for the shop. - * - * @link https://developers.etsy.com/documentation/reference#tag/Ledger-Entry - * @param mixed $date_from - * @param mixed $date_to + * Get a specific shipping profile. + * + * @param int $profile_id + * @return Etsy\Resources\ShippingProfile + */ + public function shippingProfile( + int $profile_id + ): ?ShippingProfile { + return ShippingProfile::get($this->shop_id, $profile_id); + } + + /** + * Get all reviews for the shop. + * * @param array $params - * @return Etsy\Collection[Etsy\Resources\LedgerEntry] + * @return \Etsy\Collection[Etsy\Resources\Review] */ - public function getLedgerEntries( - $date_from = false, - $date_to = false, + public function reviews( array $params = [] - ) { - // Default period is 7 days. - if(!$date_from && !$date_to) { - $date_from = Date::now()->modify('-1 week')->getTimestamp(); - $date_to = Date::now()->getTimestamp(); - } - if($date_from instanceof \DateTime) { - $date_from = $date_from->getTimestamp(); - } - if($date_to instanceof \DateTime) { - $date_to = $date_to->getTimestamp(); - } - // We don't validate wether the string is a valid timestamp. - $params['min_created'] = $date_from; - $params['max_created'] = $date_to; - return $this->request( - "GET", - "/application/shops/{$this->shop_id}/payment-account/ledger-entries", - "LedgerEntry", - $params - ) - ->append(['shop_id' => $this->shop_id]); + ): \Etsy\Collection { + return Review::all($this->shop_id, $params); } /** - * Get the specified payments for the shop. - * - * @link https://developers.etsy.com/documentation/reference#operation/getPayments - * @param array $payment_ids - * @return Etsy\Collection[Etsy\Resources\Payment] + * Get all receipts for the shop. + * + * @param array @params + * @return Etsy\Collection[Etsy\Resources\Receipt] */ - public function getPayments(array $payment_ids = []) { - return $this->request( - "GET", - "/application/shops/{$this->shop_id}/payments", - "Payment", - ["payment_ids" => $payment_ids] - ); + public function receipts( + array $params = [] + ): \Etsy\Collection { + return Receipt::all($this->shop_id, $params); } /** - * Creates a draft Etsy listing. - * - * @link https://developers.etsy.com/documentation/reference#operation/createDraftListing - * @param array $data - * @return Etsy\Resources\Listing + * Get a single receipt. + * + * @param int $receipt_id + * @return \Etsy\Resources\Receipt */ - public function createListing(array $data) { - $listing = $this->request( - "POST", - "/application/shops/{$this->shop_id}/listings", - "Listing", - $data - ); - return $listing; + public function receipt( + int $receipt_id + ): ?Receipt { + return Receipt::get($this->shop_id, $receipt_id); } /** - * Get the listings for the shop. This method should be used when querying listings for your own shop. - * - * @link https://developers.etsy.com/documentation/reference#operation/getListingsByShop + * Get all ledger entries for a shop. + * * @param array $params - * @return Etsy\Collection[Etsy\Resources\Listing] + * @return \Etsy\Collection[\Etsy\Resources\LedgerEntry] */ - public function getListings(array $params = []) { - $listings = $this->request( - "GET", - "/application/shops/{$this->shop_id}/listings", - "Listing", - $params - ); - return $listings; + public function ledgerEntries( + array $params = [] + ): \Etsy\Collection { + return LedgerEntry::all($this->shop_id, $params); } /** - * Get all active listings for a public shop. Use this method when querying listings for a public shop. - * - * @link https://developers.etsy.com/documentation/reference#operation/findAllActiveListingsByShop - * @param array $params - * @return Etsy\Collection[Etsy\Resources\Listing] + * Get a single ledger entry. + * + * @param int $ledger_entry_id + * @return Etsy\Resources\LedgerEntry */ - public function getPublicListings(array $params = []) { - $listings = $this->request( - "GET", - "/application/shops/{$this->shop_id}/listings/active", - "Listing", - $params - ); - return $listings; + public function ledgerEntry( + int $ledger_entry_id + ): ?LedgerEntry { + return LedgerEntry::get($this->shop_id, $ledger_entry_id); } /** - * Get the featured listings for the shop. - * - * @link https://developers.etsy.com/documentation/reference#operation/getFeaturedListingsByShop + * Get payments for the shop. + * + * @param int|array $payment_ids + * @return \Etsy\Collection[\Etsy\Resources\Payment] + */ + public function payments( + int|array $payment_ids + ): \Etsy\Collection { + return Payment::all($this->shop_id, $payment_ids); + } + + /** + * Get transactions for the shop. + * * @param array $params - * @return Etsy\Collection[Etsy\Resources\Listing] + * @return \Etsy\Collection[\Etsy\Resources\Transaction] */ - public function getFeaturedListings(array $params = []) { - $listings = $this->request( - "GET", - "/application/shops/{$this->shop_id}/listings/featured", - "Listing", - $params - ); - return $listings; + public function transactions( + array $params = [] + ): \Etsy\Collection { + return Transaction::all($this->shop_id, $params); } } diff --git a/src/Resources/ShopSection.php b/src/Resources/ShopSection.php index c5422cf..b95e5be 100644 --- a/src/Resources/ShopSection.php +++ b/src/Resources/ShopSection.php @@ -3,6 +3,7 @@ namespace Etsy\Resources; use Etsy\Resource; +use Etsy\Resources\Listing; /** * ShopSection resource class. Represents a Etsy shop section. @@ -13,18 +14,147 @@ class ShopSection extends Resource { /** - * Get all listings associated with the shop section. + * @var array + */ + protected $_saveable = [ + 'title' + ]; + + /** + * Get all sections for a shop. + * + * @param int $shop_id + * @return Etsy\Collection[Etsy\Resources\ShopSection] + */ + public static function all( + int $shop_id + ): \Etsy\Collection { + return self::request( + "GET", + "/application/shops/{$shop_id}/sections", + "ShopSection" + )->append(['shop_id' => $shop_id]); + } + + /** + * Get a shop section. + * + * @param int $shop_id + * @param int $section_id + * @return Etsy\Resources\ShopSection + */ + public static function get( + int $shop_id, + int $section_id + ): ?\Etsy\Resources\ShopSection { + $section = self::request( + "GET", + "/application/shops/{$shop_id}/sections/{$section_id}", + "ShopSection" + ); + if($section) { + $section->shop_id = $shop_id; + } + return $section; + } + + /** + * Create a new shop section. + * + * @param int $shop_id + * @param array $data + * @return Etsy\Resources\ShopSection + */ + public static function create( + int $shop_id, + array $data + ): ?\Etsy\Resources\ShopSection { + $section = self::request( + "POST", + "/application/shops/{$shop_id}/sections", + "ShopSection", + $data + ); + if($section) { + $section->shop_id = $shop_id; + } + return $section; + } + + /** + * Update a shop section. + * + * @param int $shop_id + * @param int $section_id + * @param array $data + * @return Etsy\Resources\ShopSection + */ + public static function update( + int $shop_id, + int $section_id, + array $data + ): ?\Etsy\Resources\ShopSection { + $section = self::request( + "PUT", + "/application/shops/{$shop_id}/sections/{$section_id}", + "ShopSection", + $data + ); + if($section) { + $section->shop_id = $shop_id; + } + return $section; + } + + /** + * Deletes a shop section. + * + * @param int $shop_id + * @param int $section_id + * @return bool + */ + public static function delete( + int $shop_id, + int $section_id + ): bool { + return self::deleteRequest( + "/application/shops/{$shop_id}/sections/{$section_id}", + ); + } + + /** + * Saves updates to the current section. * - * @link https://developers.etsy.com/documentation/reference#operation/getListingsByShopSectionId + * @param array $data + * @return Etsy\Resources\ShopSection + */ + public function save( + ?array $data = null + ): \Etsy\Resources\ShopSection { + if(!$data) { + $data = $this->getSaveData(); + } + if(count($data) == 0) { + return $this; + } + return $this->updateRequest( + "/application/shops/{$this->shop_id}/sections/{$this->shop_section_id}", + $data + ); + } + + /** + * Get all listings within this shop section. + * * @param array $params - * @return Etsy\Collection[Etsy\Resources\Listing] + * @return \Etsy\Collection[\Etsy\Resources\Listing] */ - public function getListings($params = []) { - $params['shop_section_ids'] = [$this->shop_section_id]; - return $this->request( - "GET", - "/application/shops/{$this->shop_id}/shop-sections/listings", - "Listing", + public function listings( + array $params = [] + ): \Etsy\Collection { + return Listing::allByShopSections( + $this->shop_id, + $this->shop_section_id, $params ); } diff --git a/src/Resources/Taxonomy.php b/src/Resources/Taxonomy.php deleted file mode 100644 index 41a5fbb..0000000 --- a/src/Resources/Taxonomy.php +++ /dev/null @@ -1,28 +0,0 @@ -request( - 'GET', - "/application/seller-taxonomy/nodes/{$this->id}/properties", - "TaxonomyProperty" - ); - } - -} diff --git a/src/Resources/TaxonomyProperty.php b/src/Resources/TaxonomyProperty.php deleted file mode 100644 index a5939b0..0000000 --- a/src/Resources/TaxonomyProperty.php +++ /dev/null @@ -1,13 +0,0 @@ -request( + public static function get( + string|int $user_id = null + ): ?\Etsy\Resources\User { + if(!$user_id) { + $user_id = self::me()->user_id ?? null; + } + return self::request( "GET", - "/application/user/addresses", - "UserAddress", - $params + "/application/users/{$user_id}", + "User" ); } /** - * Gets a single address for this user. - * - * @NOTE this endpoint is not yet active. - * - * @param integer/string $address_id - * @return Etsy\Resources\UserAddress + * Get basic info of the user making the request. + * + * @return ?array */ - public function getAddress($address_id) { - return $this->request( + public static function me(): ?\stdClass { + $user = Etsy::$client->get("/application/users/me"); + return isset($user->code) && $user->code == 404 ? null : $user; + } + + /** + * Get the shop for a specific user. + * + * @param int $user_id + * @return ?Etsy\Resources\Shop + */ + public static function getShop( + int $user_id = null + ): ?\Etsy\Resources\Shop { + if(!$user_id) { + $user_id = self::me()->user_id ?? null; + } + return self::request( "GET", - "/application/user/addresses/{$address_id}", - "UserAddress" + "/application/users/{$user_id}/shops", + "Shop" ); } @@ -50,12 +67,8 @@ public function getAddress($address_id) { * * @return Etsy\Resources\Shop */ - public function getShop() { - return $this->request( - "GET", - "/application/users/{$this->user_id}/shops", - "Shop" - ); + public function shop(): ?\Etsy\Resources\Shop { + return self::getShop($this->user_id); } } diff --git a/src/Resources/UserAddress.php b/src/Resources/UserAddress.php index c730a26..8729686 100644 --- a/src/Resources/UserAddress.php +++ b/src/Resources/UserAddress.php @@ -5,9 +5,59 @@ use Etsy\Resource; /** - * UserAddress resource class. Represents a User's profile Address in Etsy. + * UserAddress resource class. Represents a User's profile Address in Etsy. You can only get addresses for the currently authenticated user. * * @link https://developers.etsy.com/documentation/reference/#tag/UserAddress * @author Rhys Hall hello@rhyshall.com */ -class UserAddress extends Resource {} +class UserAddress extends Resource { + + /** + * Get all addresses for a user. + * + * @param array @params + * @return Etsy\Collection[\Etsy\Resources\UserAddress] + */ + public static function all( + array $params = [] + ): \Etsy\Collection { + return self::request( + "GET", + "/application/user/addresses", + "UserAddress", + $params + ); + } + + /** + * Get a single address for a user. + * + * @NOTE this endpoint is not yet active. + * + * @param int $address_id + * @return Etsy\Resources\UserAddress + */ + public static function get( + int $address_id + ): ?\Etsy\Resources\UserAddress { + return self::request( + "GET", + "/application/user/addresses/{$address_id}", + "UserAddress" + ); + } + + /** + * Delete a user address. This will return true if no address with the ID exists. + * + * @param int $address_id + * @return bool + */ + public static function delete( + int $address_id + ): bool { + return self::deleteRequest( + "/application/user/addresses/{$address_id}", + ); + } +}