diff --git a/CHANGELOG.md b/CHANGELOG.md index e6bff72..91546fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +## [14.4.0](https://github.com/pipedrive/client-php/compare/14.3.3...14.4.0) (2025-11-25) + +### Fixed +- API v2 configuration for the host base path: `/api/v2` instead of `/v2`. With this, API v1 configuration also changed from `/v1` to `/api/v1`, but this does not break backward compatibility as both `/api/v1` and `/v1` paths are supported for API v1. + +### Added + +- Added `POST /products/{id}/duplicate` endpoint for duplicating an existing product +- Added `deal_id` query parameter to the GET `/v2/persons` endpoint +- Added `GET /v1/leadFields` endpoint for fetching all lead fields + ## [14.3.3](https://github.com/pipedrive/client-php/compare/14.3.2...14.3.3) (2025-11-18) ### Fixed diff --git a/docs/versions/v1/Api/LeadFieldsApi.md b/docs/versions/v1/Api/LeadFieldsApi.md new file mode 100644 index 0000000..7762a9b --- /dev/null +++ b/docs/versions/v1/Api/LeadFieldsApi.md @@ -0,0 +1,75 @@ +# Pipedrive\versions\v1\LeadFieldsApi + +All URIs are relative to https://api.pipedrive.com/v1. + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**getLeadFields()**](LeadFieldsApi.md#getLeadFields) | **GET** /leadFields | Get all lead fields + + +## `getLeadFields()` + +```php +getLeadFields($start, $limit): \Pipedrive\versions\v1\Model\FieldsResponse +``` + +Get all lead fields + +Returns data about all lead fields. + +### Example + +```php +setApiKey('x-api-token', 'YOUR_API_KEY'); +// Uncomment below to setup prefix (e.g. Bearer) for API key, if needed +// $config = (new Pipedrive\versions\v1\Configuration())->setApiKeyPrefix('x-api-token', 'Bearer'); + +// Configure OAuth2 access token for authorization: oauth2 +$config = (new Pipedrive\versions\v1\Configuration())->setAccessToken('YOUR_ACCESS_TOKEN'); + + +$apiInstance = new Pipedrive\versions\v1\Api\LeadFieldsApi( + // If you want use custom http client, pass your client which implements `GuzzleHttp\ClientInterface`. + // This is optional, `GuzzleHttp\Client` will be used as default. + new GuzzleHttp\Client(), + $config +); +$start = 0; // int | Pagination start +$limit = 56; // int | Items shown per page + +try { + $result = $apiInstance->getLeadFields($start, $limit); + print_r($result); +} catch (Exception $e) { + echo 'Exception when calling LeadFieldsApi->getLeadFields: ', $e->getMessage(), PHP_EOL; +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **start** | **int**| Pagination start | [optional] [default to 0] + **limit** | **int**| Items shown per page | [optional] + +### Return type + +[**\Pipedrive\versions\v1\Model\FieldsResponse**](../Model/FieldsResponse.md) + +### Authorization + +[api_key](../README.md#api_key), [oauth2](../README.md#oauth2) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: `application/json` + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) diff --git a/docs/versions/v1/README.md b/docs/versions/v1/README.md index 5ea822f..3d1db93 100644 --- a/docs/versions/v1/README.md +++ b/docs/versions/v1/README.md @@ -350,6 +350,7 @@ Class | Method | HTTP request | Description *GoalsApi* | [**updateGoal**](Api/GoalsApi.md#updategoal) | **PUT** /goals/{id} | Update existing goal *ItemSearchApi* | [**searchItem**](Api/ItemSearchApi.md#searchitem) | **GET** /itemSearch | Perform a search from multiple item types *ItemSearchApi* | [**searchItemByField**](Api/ItemSearchApi.md#searchitembyfield) | **GET** /itemSearch/field | Perform a search using a specific field from an item type +*LeadFieldsApi* | [**getLeadFields**](Api/LeadFieldsApi.md#getleadfields) | **GET** /leadFields | Get all lead fields *LeadLabelsApi* | [**addLeadLabel**](Api/LeadLabelsApi.md#addleadlabel) | **POST** /leadLabels | Add a lead label *LeadLabelsApi* | [**deleteLeadLabel**](Api/LeadLabelsApi.md#deleteleadlabel) | **DELETE** /leadLabels/{id} | Delete a lead label *LeadLabelsApi* | [**getLeadLabels**](Api/LeadLabelsApi.md#getleadlabels) | **GET** /leadLabels | Get all lead labels diff --git a/docs/versions/v2/Api/PersonsApi.md b/docs/versions/v2/Api/PersonsApi.md index 8481b0a..847a638 100644 --- a/docs/versions/v2/Api/PersonsApi.md +++ b/docs/versions/v2/Api/PersonsApi.md @@ -490,7 +490,7 @@ Name | Type | Description | Notes ## `getPersons()` ```php -getPersons($filter_id, $ids, $owner_id, $org_id, $updated_since, $updated_until, $sort_by, $sort_direction, $include_fields, $custom_fields, $limit, $cursor): \Pipedrive\versions\v2\Model\GetPersons +getPersons($filter_id, $ids, $owner_id, $org_id, $deal_id, $updated_since, $updated_until, $sort_by, $sort_direction, $include_fields, $custom_fields, $limit, $cursor): \Pipedrive\versions\v2\Model\GetPersons ``` Get all persons @@ -523,6 +523,7 @@ $filter_id = 56; // int | If supplied, only persons matching the specified filte $ids = 'ids_example'; // string | Optional comma separated string array of up to 100 entity ids to fetch. If filter_id is provided, this is ignored. If any of the requested entities do not exist or are not visible, they are not included in the response. $owner_id = 56; // int | If supplied, only persons owned by the specified user are returned. If filter_id is provided, this is ignored. $org_id = 56; // int | If supplied, only persons linked to the specified organization are returned. If filter_id is provided, this is ignored. +$deal_id = 56; // int | If supplied, only persons linked to the specified deal are returned. If filter_id is provided, this is ignored. $updated_since = 'updated_since_example'; // string | If set, only persons with an `update_time` later than or equal to this time are returned. In RFC3339 format, e.g. 2025-01-01T10:20:00Z. $updated_until = 'updated_until_example'; // string | If set, only persons with an `update_time` earlier than this time are returned. In RFC3339 format, e.g. 2025-01-01T10:20:00Z. $sort_by = 'id'; // string | The field to sort by. Supported fields: `id`, `update_time`, `add_time`. @@ -533,7 +534,7 @@ $limit = 100; // int | For pagination, the limit of entries to be returned. If n $cursor = 'cursor_example'; // string | For pagination, the marker (an opaque string value) representing the first item on the next page try { - $result = $apiInstance->getPersons($filter_id, $ids, $owner_id, $org_id, $updated_since, $updated_until, $sort_by, $sort_direction, $include_fields, $custom_fields, $limit, $cursor); + $result = $apiInstance->getPersons($filter_id, $ids, $owner_id, $org_id, $deal_id, $updated_since, $updated_until, $sort_by, $sort_direction, $include_fields, $custom_fields, $limit, $cursor); print_r($result); } catch (Exception $e) { echo 'Exception when calling PersonsApi->getPersons: ', $e->getMessage(), PHP_EOL; @@ -548,6 +549,7 @@ Name | Type | Description | Notes **ids** | **string**| Optional comma separated string array of up to 100 entity ids to fetch. If filter_id is provided, this is ignored. If any of the requested entities do not exist or are not visible, they are not included in the response. | [optional] **owner_id** | **int**| If supplied, only persons owned by the specified user are returned. If filter_id is provided, this is ignored. | [optional] **org_id** | **int**| If supplied, only persons linked to the specified organization are returned. If filter_id is provided, this is ignored. | [optional] + **deal_id** | **int**| If supplied, only persons linked to the specified deal are returned. If filter_id is provided, this is ignored. | [optional] **updated_since** | **string**| If set, only persons with an `update_time` later than or equal to this time are returned. In RFC3339 format, e.g. 2025-01-01T10:20:00Z. | [optional] **updated_until** | **string**| If set, only persons with an `update_time` earlier than this time are returned. In RFC3339 format, e.g. 2025-01-01T10:20:00Z. | [optional] **sort_by** | **string**| The field to sort by. Supported fields: `id`, `update_time`, `add_time`. | [optional] [default to 'id'] diff --git a/docs/versions/v2/Api/ProductsApi.md b/docs/versions/v2/Api/ProductsApi.md index c907246..62a663c 100644 --- a/docs/versions/v2/Api/ProductsApi.md +++ b/docs/versions/v2/Api/ProductsApi.md @@ -11,6 +11,7 @@ Method | HTTP request | Description [**deleteProductFollower()**](ProductsApi.md#deleteProductFollower) | **DELETE** /products/{id}/followers/{follower_id} | Delete a follower from a product [**deleteProductImage()**](ProductsApi.md#deleteProductImage) | **DELETE** /products/{id}/images | Delete an image of a product [**deleteProductVariation()**](ProductsApi.md#deleteProductVariation) | **DELETE** /products/{id}/variations/{product_variation_id} | Delete a product variation +[**duplicateProduct()**](ProductsApi.md#duplicateProduct) | **POST** /products/{id}/duplicate | Duplicate a product [**getProduct()**](ProductsApi.md#getProduct) | **GET** /products/{id} | Get one product [**getProductFollowers()**](ProductsApi.md#getProductFollowers) | **GET** /products/{id}/followers | List followers of a product [**getProductFollowersChangelog()**](ProductsApi.md#getProductFollowersChangelog) | **GET** /products/{id}/followers/changelog | List followers changelog of a product @@ -487,6 +488,71 @@ Name | Type | Description | Notes [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +## `duplicateProduct()` + +```php +duplicateProduct($id): \Pipedrive\versions\v2\Model\ProductResponse +``` + +Duplicate a product + +Creates a duplicate of an existing product including all variations, prices, and custom fields. + +### Example + +```php +setApiKey('x-api-token', 'YOUR_API_KEY'); +// Uncomment below to setup prefix (e.g. Bearer) for API key, if needed +// $config = (new Pipedrive\versions\v2\Configuration())->setApiKeyPrefix('x-api-token', 'Bearer'); + +// Configure OAuth2 access token for authorization: oauth2 +$config = (new Pipedrive\versions\v2\Configuration())->setAccessToken('YOUR_ACCESS_TOKEN'); + + +$apiInstance = new Pipedrive\versions\v2\Api\ProductsApi( + // If you want use custom http client, pass your client which implements `GuzzleHttp\ClientInterface`. + // This is optional, `GuzzleHttp\Client` will be used as default. + new GuzzleHttp\Client(), + $config +); +$id = 56; // int | The ID of the product + +try { + $result = $apiInstance->duplicateProduct($id); + print_r($result); +} catch (Exception $e) { + echo 'Exception when calling ProductsApi->duplicateProduct: ', $e->getMessage(), PHP_EOL; +} +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **id** | **int**| The ID of the product | + +### Return type + +[**\Pipedrive\versions\v2\Model\ProductResponse**](../Model/ProductResponse.md) + +### Authorization + +[api_key](../README.md#api_key), [oauth2](../README.md#oauth2) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: `application/json` + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + ## `getProduct()` ```php diff --git a/docs/versions/v2/README.md b/docs/versions/v2/README.md index aca516b..b04ddf4 100644 --- a/docs/versions/v2/README.md +++ b/docs/versions/v2/README.md @@ -347,6 +347,7 @@ Class | Method | HTTP request | Description *ProductsApi* | [**deleteProductFollower**](Api/ProductsApi.md#deleteproductfollower) | **DELETE** /products/{id}/followers/{follower_id} | Delete a follower from a product *ProductsApi* | [**deleteProductImage**](Api/ProductsApi.md#deleteproductimage) | **DELETE** /products/{id}/images | Delete an image of a product *ProductsApi* | [**deleteProductVariation**](Api/ProductsApi.md#deleteproductvariation) | **DELETE** /products/{id}/variations/{product_variation_id} | Delete a product variation +*ProductsApi* | [**duplicateProduct**](Api/ProductsApi.md#duplicateproduct) | **POST** /products/{id}/duplicate | Duplicate a product *ProductsApi* | [**getProduct**](Api/ProductsApi.md#getproduct) | **GET** /products/{id} | Get one product *ProductsApi* | [**getProductFollowers**](Api/ProductsApi.md#getproductfollowers) | **GET** /products/{id}/followers | List followers of a product *ProductsApi* | [**getProductFollowersChangelog**](Api/ProductsApi.md#getproductfollowerschangelog) | **GET** /products/{id}/followers/changelog | List followers changelog of a product diff --git a/lib/versions/v1/Api/LeadFieldsApi.php b/lib/versions/v1/Api/LeadFieldsApi.php new file mode 100644 index 0000000..4651791 --- /dev/null +++ b/lib/versions/v1/Api/LeadFieldsApi.php @@ -0,0 +1,445 @@ +client = $client ?: new Client(); + $this->config = $config ?: new Configuration(); + $this->headerSelector = $selector ?: new HeaderSelector(); + $this->hostIndex = $hostIndex; + } + + /** + * Set the host index + * + * @param int $hostIndex Host index (required) + */ + public function setHostIndex(int $hostIndex): void + { + $this->hostIndex = $hostIndex; + } + + /** + * Get the host index + * + * @return int Host index + */ + public function getHostIndex(): int + { + return $this->hostIndex; + } + + /** + * @return Configuration + */ + public function getConfig(): Configuration + { + return $this->config; + } + + /** + * Operation getLeadFields + * + * Get all lead fields + * + * @param int|0 $start Pagination start (optional, default to 0) + * @param int|null $limit Items shown per page (optional) + * + * @throws ApiException on non-2xx response + * @throws InvalidArgumentException|GuzzleException + * @return \Pipedrive\versions\v1\Model\FieldsResponse + */ + public function getLeadFields($start = 0, $limit = null) + { + list($response) = $this->getLeadFieldsWithHttpInfo($start, $limit); + return $response; + } + + /** + * Operation getLeadFieldsWithHttpInfo + * + * Get all lead fields + * + * @param int|0 $start Pagination start (optional, default to 0) + * @param int|null $limit Items shown per page (optional) + * + * @throws ApiException on non-2xx response + * @throws InvalidArgumentException|GuzzleException + * @return array of \Pipedrive\versions\v1\Model\FieldsResponse, HTTP status code, HTTP response headers (array of strings) + */ + public function getLeadFieldsWithHttpInfo($start = 0, $limit = null) + { + $request = $this->getLeadFieldsRequest($start, $limit); + + try { + $options = $this->createHttpClientOption(); + try { + $response = $this->client->send($request, $options); + } catch (RequestException $e) { + if ($e->getCode() === 401 && $this->config->isRefreshPossible()) { + $this->config->refreshToken(); + $request = $this->getLeadFieldsRequest($start, $limit); + $response = $this->client->send($request, $options); + } else { + throw new ApiException( + "[{$e->getCode()}] {$e->getMessage()}", + (int) $e->getCode(), + $e->getResponse() ? $e->getResponse()->getHeaders() : null, + $e->getResponse() ? (string) $e->getResponse()->getBody() : null + ); + } + } catch (ConnectException $e) { + throw new ApiException( + "[{$e->getCode()}] {$e->getMessage()}", + (int) $e->getCode(), + null, + null + ); + } + + $statusCode = $response->getStatusCode(); + + + switch($statusCode) { + case 200: + /* @phpstan-ignore-next-line */ + if ('\Pipedrive\versions\v1\Model\FieldsResponse' === '\SplFileObject') { + $content = $response->getBody(); //stream goes to serializer + } else { + $content = (string) $response->getBody(); + } + + return [ + ObjectSerializer::deserialize($content, '\Pipedrive\versions\v1\Model\FieldsResponse', []), + $response->getStatusCode(), + $response->getHeaders() + ]; + } + + if ($statusCode < 200 || $statusCode > 299) { + throw new ApiException( + sprintf( + '[%d] Error connecting to the API (%s)', + $statusCode, + (string) $request->getUri() + ), + $statusCode, + $response->getHeaders(), + (string) $response->getBody() + ); + } + + /* @phpstan-ignore-next-line */ + if ('\Pipedrive\versions\v1\Model\FieldsResponse' === '\SplFileObject') { + $content = $response->getBody(); //stream goes to serializer + } else { + $content = (string) $response->getBody(); + } + + return [ + ObjectSerializer::deserialize($content, '\Pipedrive\versions\v1\Model\FieldsResponse', []), + $response->getStatusCode(), + $response->getHeaders() + ]; + + } catch (ApiException $e) { + switch ($e->getCode()) { + case 200: + $data = ObjectSerializer::deserialize( + $e->getResponseBody(), + '\Pipedrive\versions\v1\Model\FieldsResponse', + $e->getResponseHeaders() + ); + $e->setResponseObject($data); + break; + } + throw $e; + } + } + + /** + * Operation getLeadFieldsAsync + * + * Get all lead fields + * + * @param int|0 $start Pagination start (optional, default to 0) + * @param int|null $limit Items shown per page (optional) + * + * @throws InvalidArgumentException|OAuthProviderException + * @return PromiseInterface + */ + public function getLeadFieldsAsync($start = 0, $limit = null): PromiseInterface + { + return $this->getLeadFieldsAsyncWithHttpInfo($start, $limit) + ->then( + function ($response) { + return $response[0]; + } + ); + } + + /** + * Operation getLeadFieldsAsyncWithHttpInfo + * + * Get all lead fields + * + * @param int|0 $start Pagination start (optional, default to 0) + * @param int|null $limit Items shown per page (optional) + * + * @throws InvalidArgumentException|OAuthProviderException + * @return PromiseInterface + */ + public function getLeadFieldsAsyncWithHttpInfo($start = 0, $limit = null): PromiseInterface + { + $returnType = '\Pipedrive\versions\v1\Model\FieldsResponse'; + $request = $this->getLeadFieldsRequest($start, $limit); + + return $this->client + ->sendAsync($request, $this->createHttpClientOption()) + ->then( + function ($response) use ($returnType) { + /* @phpstan-ignore-next-line */ + if ($returnType === '\SplFileObject') { + $content = $response->getBody(); //stream goes to serializer + } else { + $content = (string) $response->getBody(); + } + + return [ + ObjectSerializer::deserialize($content, $returnType, []), + $response->getStatusCode(), + $response->getHeaders() + ]; + }, + function ($exception) { + $response = $exception->getResponse(); + $statusCode = $response->getStatusCode(); + throw new ApiException( + sprintf( + '[%d] Error connecting to the API (%s)', + $statusCode, + $exception->getRequest()->getUri() + ), + $statusCode, + $response->getHeaders(), + (string) $response->getBody() + ); + } + ); + } + + /** + * Create request for operation 'getLeadFields' + * + * @param int|0 $start Pagination start (optional, default to 0) + * @param int|null $limit Items shown per page (optional) + * + * @throws InvalidArgumentException|OAuthProviderException + * @return Request + */ + public function getLeadFieldsRequest($start = 0, $limit = null): Request + { + + $resourcePath = '/leadFields'; + $formParams = []; + $queryParams = []; + $headerParams = []; + $httpBody = ''; + $multipart = false; + + // query params + /* @phpstan-ignore-next-line */ + if (is_array($start)) { + $start = ObjectSerializer::serializeCollection($start, '', true); + } + if ($start !== null) { + $queryParams['start'] = $start; + } + // query params + /* @phpstan-ignore-next-line */ + if (is_array($limit)) { + $limit = ObjectSerializer::serializeCollection($limit, '', true); + } + if ($limit !== null) { + $queryParams['limit'] = $limit; + } + + + + + /* @phpstan-ignore-next-line */ + if ($multipart) { + $headers = $this->headerSelector->selectHeadersForMultipart( + ['application/json'] + ); + } else { + $headers = $this->headerSelector->selectHeaders( + ['application/json'], + [] + ); + } + + // for model (json/xml) + if (count($formParams) > 0) { + /* @phpstan-ignore-next-line */ + if ($multipart) { + $multipartContents = []; + foreach ($formParams as $formParamName => $formParamValue) { + $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue]; + foreach ($formParamValueItems as $formParamValueItem) { + $multipartContents[] = [ + 'name' => $formParamName, + 'contents' => $formParamValueItem + ]; + } + } + // for HTTP post (form) + $httpBody = new MultipartStream($multipartContents); + + } elseif ($headers['Content-Type'] === 'application/json') { + $httpBody = Utils::jsonEncode($formParams); + + } else { + // for HTTP post (form) + $httpBody = Query::build($formParams); + } + } + + // this endpoint requires API key authentication + $apiKey = $this->config->getApiKeyWithPrefix('x-api-token'); + if ($apiKey !== null) { + $headers['x-api-token'] = $apiKey; + } + // this endpoint requires OAuth (access token) + if ($this->config->getAccessToken() !== null) { + // If access token is expired + if ($this->config->isRefreshPossible() && $this->config->getExpiresAt() <= time()) { + $this->config->refreshToken(); + } + $headers['Authorization'] = 'Bearer ' . $this->config->getAccessToken(); + } + + $defaultHeaders = []; + if ($this->config->getUserAgent()) { + $defaultHeaders['User-Agent'] = $this->config->getUserAgent(); + } + + $headers = array_merge( + $defaultHeaders, + $headerParams, + $headers + ); + + $query = Query::build($queryParams); + return new Request( + 'GET', + $this->config->getHost() . $resourcePath . ($query ? "?{$query}" : ''), + $headers, + $httpBody + ); + } + + /** + * Create http client option + * + * @throws RuntimeException on file opening failure + * @return array of http client options + */ + protected function createHttpClientOption(): array + { + $options = []; + if ($this->config->getDebug()) { + $options[RequestOptions::DEBUG] = fopen($this->config->getDebugFile(), 'a'); + if (!$options[RequestOptions::DEBUG]) { + throw new RuntimeException('Failed to open the debug file: ' . $this->config->getDebugFile()); + } + } + + return $options; + } +} diff --git a/lib/versions/v1/Configuration.php b/lib/versions/v1/Configuration.php index 0a88676..682c41a 100644 --- a/lib/versions/v1/Configuration.php +++ b/lib/versions/v1/Configuration.php @@ -674,7 +674,7 @@ public function updateOAuthRelatedFields(object $oAuthToken): Configuration } if (property_exists($oAuthToken, 'api_domain') && $oAuthToken->api_domain !== null) { - $this->setHost($oAuthToken->api_domain.'/v1'); + $this->setHost($oAuthToken->api_domain.'/api/v1'); } if (is_callable($this->getOAuthTokenUpdateCallback())) { @@ -847,7 +847,7 @@ public function getHostSettings(): array { return [ [ - "url" => "https://api.pipedrive.com/v1", + "url" => "https://api.pipedrive.com/api/v1", "description" => "No description provided", ] ]; diff --git a/lib/versions/v2/Api/PersonsApi.php b/lib/versions/v2/Api/PersonsApi.php index 03d4bc8..575157e 100644 --- a/lib/versions/v2/Api/PersonsApi.php +++ b/lib/versions/v2/Api/PersonsApi.php @@ -2303,6 +2303,7 @@ public function getPersonFollowersChangelogRequest($id, $limit = null, $cursor = * @param string|null $ids Optional comma separated string array of up to 100 entity ids to fetch. If filter_id is provided, this is ignored. If any of the requested entities do not exist or are not visible, they are not included in the response. (optional) * @param int|null $owner_id If supplied, only persons owned by the specified user are returned. If filter_id is provided, this is ignored. (optional) * @param int|null $org_id If supplied, only persons linked to the specified organization are returned. If filter_id is provided, this is ignored. (optional) + * @param int|null $deal_id If supplied, only persons linked to the specified deal are returned. If filter_id is provided, this is ignored. (optional) * @param string|null $updated_since If set, only persons with an `update_time` later than or equal to this time are returned. In RFC3339 format, e.g. 2025-01-01T10:20:00Z. (optional) * @param string|null $updated_until If set, only persons with an `update_time` earlier than this time are returned. In RFC3339 format, e.g. 2025-01-01T10:20:00Z. (optional) * @param string|'id' $sort_by The field to sort by. Supported fields: `id`, `update_time`, `add_time`. (optional, default to 'id') @@ -2316,9 +2317,9 @@ public function getPersonFollowersChangelogRequest($id, $limit = null, $cursor = * @throws InvalidArgumentException|GuzzleException * @return \Pipedrive\versions\v2\Model\GetPersons */ - public function getPersons($filter_id = null, $ids = null, $owner_id = null, $org_id = null, $updated_since = null, $updated_until = null, $sort_by = 'id', $sort_direction = 'asc', $include_fields = null, $custom_fields = null, $limit = null, $cursor = null) + public function getPersons($filter_id = null, $ids = null, $owner_id = null, $org_id = null, $deal_id = null, $updated_since = null, $updated_until = null, $sort_by = 'id', $sort_direction = 'asc', $include_fields = null, $custom_fields = null, $limit = null, $cursor = null) { - list($response) = $this->getPersonsWithHttpInfo($filter_id, $ids, $owner_id, $org_id, $updated_since, $updated_until, $sort_by, $sort_direction, $include_fields, $custom_fields, $limit, $cursor); + list($response) = $this->getPersonsWithHttpInfo($filter_id, $ids, $owner_id, $org_id, $deal_id, $updated_since, $updated_until, $sort_by, $sort_direction, $include_fields, $custom_fields, $limit, $cursor); return $response; } @@ -2331,6 +2332,7 @@ public function getPersons($filter_id = null, $ids = null, $owner_id = null, $or * @param string|null $ids Optional comma separated string array of up to 100 entity ids to fetch. If filter_id is provided, this is ignored. If any of the requested entities do not exist or are not visible, they are not included in the response. (optional) * @param int|null $owner_id If supplied, only persons owned by the specified user are returned. If filter_id is provided, this is ignored. (optional) * @param int|null $org_id If supplied, only persons linked to the specified organization are returned. If filter_id is provided, this is ignored. (optional) + * @param int|null $deal_id If supplied, only persons linked to the specified deal are returned. If filter_id is provided, this is ignored. (optional) * @param string|null $updated_since If set, only persons with an `update_time` later than or equal to this time are returned. In RFC3339 format, e.g. 2025-01-01T10:20:00Z. (optional) * @param string|null $updated_until If set, only persons with an `update_time` earlier than this time are returned. In RFC3339 format, e.g. 2025-01-01T10:20:00Z. (optional) * @param string|'id' $sort_by The field to sort by. Supported fields: `id`, `update_time`, `add_time`. (optional, default to 'id') @@ -2344,9 +2346,9 @@ public function getPersons($filter_id = null, $ids = null, $owner_id = null, $or * @throws InvalidArgumentException|GuzzleException * @return array of \Pipedrive\versions\v2\Model\GetPersons, HTTP status code, HTTP response headers (array of strings) */ - public function getPersonsWithHttpInfo($filter_id = null, $ids = null, $owner_id = null, $org_id = null, $updated_since = null, $updated_until = null, $sort_by = 'id', $sort_direction = 'asc', $include_fields = null, $custom_fields = null, $limit = null, $cursor = null) + public function getPersonsWithHttpInfo($filter_id = null, $ids = null, $owner_id = null, $org_id = null, $deal_id = null, $updated_since = null, $updated_until = null, $sort_by = 'id', $sort_direction = 'asc', $include_fields = null, $custom_fields = null, $limit = null, $cursor = null) { - $request = $this->getPersonsRequest($filter_id, $ids, $owner_id, $org_id, $updated_since, $updated_until, $sort_by, $sort_direction, $include_fields, $custom_fields, $limit, $cursor); + $request = $this->getPersonsRequest($filter_id, $ids, $owner_id, $org_id, $deal_id, $updated_since, $updated_until, $sort_by, $sort_direction, $include_fields, $custom_fields, $limit, $cursor); try { $options = $this->createHttpClientOption(); @@ -2355,7 +2357,7 @@ public function getPersonsWithHttpInfo($filter_id = null, $ids = null, $owner_id } catch (RequestException $e) { if ($e->getCode() === 401 && $this->config->isRefreshPossible()) { $this->config->refreshToken(); - $request = $this->getPersonsRequest($filter_id, $ids, $owner_id, $org_id, $updated_since, $updated_until, $sort_by, $sort_direction, $include_fields, $custom_fields, $limit, $cursor); + $request = $this->getPersonsRequest($filter_id, $ids, $owner_id, $org_id, $deal_id, $updated_since, $updated_until, $sort_by, $sort_direction, $include_fields, $custom_fields, $limit, $cursor); $response = $this->client->send($request, $options); } else { throw new ApiException( @@ -2443,6 +2445,7 @@ public function getPersonsWithHttpInfo($filter_id = null, $ids = null, $owner_id * @param string|null $ids Optional comma separated string array of up to 100 entity ids to fetch. If filter_id is provided, this is ignored. If any of the requested entities do not exist or are not visible, they are not included in the response. (optional) * @param int|null $owner_id If supplied, only persons owned by the specified user are returned. If filter_id is provided, this is ignored. (optional) * @param int|null $org_id If supplied, only persons linked to the specified organization are returned. If filter_id is provided, this is ignored. (optional) + * @param int|null $deal_id If supplied, only persons linked to the specified deal are returned. If filter_id is provided, this is ignored. (optional) * @param string|null $updated_since If set, only persons with an `update_time` later than or equal to this time are returned. In RFC3339 format, e.g. 2025-01-01T10:20:00Z. (optional) * @param string|null $updated_until If set, only persons with an `update_time` earlier than this time are returned. In RFC3339 format, e.g. 2025-01-01T10:20:00Z. (optional) * @param string|'id' $sort_by The field to sort by. Supported fields: `id`, `update_time`, `add_time`. (optional, default to 'id') @@ -2455,9 +2458,9 @@ public function getPersonsWithHttpInfo($filter_id = null, $ids = null, $owner_id * @throws InvalidArgumentException|OAuthProviderException * @return PromiseInterface */ - public function getPersonsAsync($filter_id = null, $ids = null, $owner_id = null, $org_id = null, $updated_since = null, $updated_until = null, $sort_by = 'id', $sort_direction = 'asc', $include_fields = null, $custom_fields = null, $limit = null, $cursor = null): PromiseInterface + public function getPersonsAsync($filter_id = null, $ids = null, $owner_id = null, $org_id = null, $deal_id = null, $updated_since = null, $updated_until = null, $sort_by = 'id', $sort_direction = 'asc', $include_fields = null, $custom_fields = null, $limit = null, $cursor = null): PromiseInterface { - return $this->getPersonsAsyncWithHttpInfo($filter_id, $ids, $owner_id, $org_id, $updated_since, $updated_until, $sort_by, $sort_direction, $include_fields, $custom_fields, $limit, $cursor) + return $this->getPersonsAsyncWithHttpInfo($filter_id, $ids, $owner_id, $org_id, $deal_id, $updated_since, $updated_until, $sort_by, $sort_direction, $include_fields, $custom_fields, $limit, $cursor) ->then( function ($response) { return $response[0]; @@ -2474,6 +2477,7 @@ function ($response) { * @param string|null $ids Optional comma separated string array of up to 100 entity ids to fetch. If filter_id is provided, this is ignored. If any of the requested entities do not exist or are not visible, they are not included in the response. (optional) * @param int|null $owner_id If supplied, only persons owned by the specified user are returned. If filter_id is provided, this is ignored. (optional) * @param int|null $org_id If supplied, only persons linked to the specified organization are returned. If filter_id is provided, this is ignored. (optional) + * @param int|null $deal_id If supplied, only persons linked to the specified deal are returned. If filter_id is provided, this is ignored. (optional) * @param string|null $updated_since If set, only persons with an `update_time` later than or equal to this time are returned. In RFC3339 format, e.g. 2025-01-01T10:20:00Z. (optional) * @param string|null $updated_until If set, only persons with an `update_time` earlier than this time are returned. In RFC3339 format, e.g. 2025-01-01T10:20:00Z. (optional) * @param string|'id' $sort_by The field to sort by. Supported fields: `id`, `update_time`, `add_time`. (optional, default to 'id') @@ -2486,10 +2490,10 @@ function ($response) { * @throws InvalidArgumentException|OAuthProviderException * @return PromiseInterface */ - public function getPersonsAsyncWithHttpInfo($filter_id = null, $ids = null, $owner_id = null, $org_id = null, $updated_since = null, $updated_until = null, $sort_by = 'id', $sort_direction = 'asc', $include_fields = null, $custom_fields = null, $limit = null, $cursor = null): PromiseInterface + public function getPersonsAsyncWithHttpInfo($filter_id = null, $ids = null, $owner_id = null, $org_id = null, $deal_id = null, $updated_since = null, $updated_until = null, $sort_by = 'id', $sort_direction = 'asc', $include_fields = null, $custom_fields = null, $limit = null, $cursor = null): PromiseInterface { $returnType = '\Pipedrive\versions\v2\Model\GetPersons'; - $request = $this->getPersonsRequest($filter_id, $ids, $owner_id, $org_id, $updated_since, $updated_until, $sort_by, $sort_direction, $include_fields, $custom_fields, $limit, $cursor); + $request = $this->getPersonsRequest($filter_id, $ids, $owner_id, $org_id, $deal_id, $updated_since, $updated_until, $sort_by, $sort_direction, $include_fields, $custom_fields, $limit, $cursor); return $this->client ->sendAsync($request, $this->createHttpClientOption()) @@ -2532,6 +2536,7 @@ function ($exception) { * @param string|null $ids Optional comma separated string array of up to 100 entity ids to fetch. If filter_id is provided, this is ignored. If any of the requested entities do not exist or are not visible, they are not included in the response. (optional) * @param int|null $owner_id If supplied, only persons owned by the specified user are returned. If filter_id is provided, this is ignored. (optional) * @param int|null $org_id If supplied, only persons linked to the specified organization are returned. If filter_id is provided, this is ignored. (optional) + * @param int|null $deal_id If supplied, only persons linked to the specified deal are returned. If filter_id is provided, this is ignored. (optional) * @param string|null $updated_since If set, only persons with an `update_time` later than or equal to this time are returned. In RFC3339 format, e.g. 2025-01-01T10:20:00Z. (optional) * @param string|null $updated_until If set, only persons with an `update_time` earlier than this time are returned. In RFC3339 format, e.g. 2025-01-01T10:20:00Z. (optional) * @param string|'id' $sort_by The field to sort by. Supported fields: `id`, `update_time`, `add_time`. (optional, default to 'id') @@ -2544,7 +2549,7 @@ function ($exception) { * @throws InvalidArgumentException|OAuthProviderException * @return Request */ - public function getPersonsRequest($filter_id = null, $ids = null, $owner_id = null, $org_id = null, $updated_since = null, $updated_until = null, $sort_by = 'id', $sort_direction = 'asc', $include_fields = null, $custom_fields = null, $limit = null, $cursor = null): Request + public function getPersonsRequest($filter_id = null, $ids = null, $owner_id = null, $org_id = null, $deal_id = null, $updated_since = null, $updated_until = null, $sort_by = 'id', $sort_direction = 'asc', $include_fields = null, $custom_fields = null, $limit = null, $cursor = null): Request { $resourcePath = '/persons'; @@ -2588,6 +2593,14 @@ public function getPersonsRequest($filter_id = null, $ids = null, $owner_id = nu } // query params /* @phpstan-ignore-next-line */ + if (is_array($deal_id)) { + $deal_id = ObjectSerializer::serializeCollection($deal_id, '', true); + } + if ($deal_id !== null) { + $queryParams['deal_id'] = $deal_id; + } + // query params + /* @phpstan-ignore-next-line */ if (is_array($updated_since)) { $updated_since = ObjectSerializer::serializeCollection($updated_since, '', true); } diff --git a/lib/versions/v2/Api/ProductsApi.php b/lib/versions/v2/Api/ProductsApi.php index 8b1941c..bf85cae 100644 --- a/lib/versions/v2/Api/ProductsApi.php +++ b/lib/versions/v2/Api/ProductsApi.php @@ -2247,6 +2247,302 @@ public function deleteProductVariationRequest($id, $product_variation_id): Reque ); } + /** + * Operation duplicateProduct + * + * Duplicate a product + * + * @param int $id The ID of the product (required) + * + * @throws ApiException on non-2xx response + * @throws InvalidArgumentException|GuzzleException + * @return \Pipedrive\versions\v2\Model\ProductResponse + */ + public function duplicateProduct($id) + { + list($response) = $this->duplicateProductWithHttpInfo($id); + return $response; + } + + /** + * Operation duplicateProductWithHttpInfo + * + * Duplicate a product + * + * @param int $id The ID of the product (required) + * + * @throws ApiException on non-2xx response + * @throws InvalidArgumentException|GuzzleException + * @return array of \Pipedrive\versions\v2\Model\ProductResponse, HTTP status code, HTTP response headers (array of strings) + */ + public function duplicateProductWithHttpInfo($id) + { + $request = $this->duplicateProductRequest($id); + + try { + $options = $this->createHttpClientOption(); + try { + $response = $this->client->send($request, $options); + } catch (RequestException $e) { + if ($e->getCode() === 401 && $this->config->isRefreshPossible()) { + $this->config->refreshToken(); + $request = $this->duplicateProductRequest($id); + $response = $this->client->send($request, $options); + } else { + throw new ApiException( + "[{$e->getCode()}] {$e->getMessage()}", + (int) $e->getCode(), + $e->getResponse() ? $e->getResponse()->getHeaders() : null, + $e->getResponse() ? (string) $e->getResponse()->getBody() : null + ); + } + } catch (ConnectException $e) { + throw new ApiException( + "[{$e->getCode()}] {$e->getMessage()}", + (int) $e->getCode(), + null, + null + ); + } + + $statusCode = $response->getStatusCode(); + + + switch($statusCode) { + case 201: + /* @phpstan-ignore-next-line */ + if ('\Pipedrive\versions\v2\Model\ProductResponse' === '\SplFileObject') { + $content = $response->getBody(); //stream goes to serializer + } else { + $content = (string) $response->getBody(); + } + + return [ + ObjectSerializer::deserialize($content, '\Pipedrive\versions\v2\Model\ProductResponse', []), + $response->getStatusCode(), + $response->getHeaders() + ]; + } + + if ($statusCode < 200 || $statusCode > 299) { + throw new ApiException( + sprintf( + '[%d] Error connecting to the API (%s)', + $statusCode, + (string) $request->getUri() + ), + $statusCode, + $response->getHeaders(), + (string) $response->getBody() + ); + } + + /* @phpstan-ignore-next-line */ + if ('\Pipedrive\versions\v2\Model\ProductResponse' === '\SplFileObject') { + $content = $response->getBody(); //stream goes to serializer + } else { + $content = (string) $response->getBody(); + } + + return [ + ObjectSerializer::deserialize($content, '\Pipedrive\versions\v2\Model\ProductResponse', []), + $response->getStatusCode(), + $response->getHeaders() + ]; + + } catch (ApiException $e) { + switch ($e->getCode()) { + case 201: + $data = ObjectSerializer::deserialize( + $e->getResponseBody(), + '\Pipedrive\versions\v2\Model\ProductResponse', + $e->getResponseHeaders() + ); + $e->setResponseObject($data); + break; + } + throw $e; + } + } + + /** + * Operation duplicateProductAsync + * + * Duplicate a product + * + * @param int $id The ID of the product (required) + * + * @throws InvalidArgumentException|OAuthProviderException + * @return PromiseInterface + */ + public function duplicateProductAsync($id): PromiseInterface + { + return $this->duplicateProductAsyncWithHttpInfo($id) + ->then( + function ($response) { + return $response[0]; + } + ); + } + + /** + * Operation duplicateProductAsyncWithHttpInfo + * + * Duplicate a product + * + * @param int $id The ID of the product (required) + * + * @throws InvalidArgumentException|OAuthProviderException + * @return PromiseInterface + */ + public function duplicateProductAsyncWithHttpInfo($id): PromiseInterface + { + $returnType = '\Pipedrive\versions\v2\Model\ProductResponse'; + $request = $this->duplicateProductRequest($id); + + return $this->client + ->sendAsync($request, $this->createHttpClientOption()) + ->then( + function ($response) use ($returnType) { + /* @phpstan-ignore-next-line */ + if ($returnType === '\SplFileObject') { + $content = $response->getBody(); //stream goes to serializer + } else { + $content = (string) $response->getBody(); + } + + return [ + ObjectSerializer::deserialize($content, $returnType, []), + $response->getStatusCode(), + $response->getHeaders() + ]; + }, + function ($exception) { + $response = $exception->getResponse(); + $statusCode = $response->getStatusCode(); + throw new ApiException( + sprintf( + '[%d] Error connecting to the API (%s)', + $statusCode, + $exception->getRequest()->getUri() + ), + $statusCode, + $response->getHeaders(), + (string) $response->getBody() + ); + } + ); + } + + /** + * Create request for operation 'duplicateProduct' + * + * @param int $id The ID of the product (required) + * + * @throws InvalidArgumentException|OAuthProviderException + * @return Request + */ + public function duplicateProductRequest($id): Request + { + // verify the required parameter 'id' is set + /* @phpstan-ignore-next-line */ + if ($id === null || (is_array($id) && count($id) === 0)) { + throw new \InvalidArgumentException( + 'Missing the required parameter $id when calling duplicateProduct' + ); + } + + $resourcePath = '/products/{id}/duplicate'; + $formParams = []; + $queryParams = []; + $headerParams = []; + $httpBody = ''; + $multipart = false; + + + + // path params + if ($id !== null) { + $resourcePath = str_replace( + '{' . 'id' . '}', + ObjectSerializer::toPathValue($id), + $resourcePath + ); + } + + + /* @phpstan-ignore-next-line */ + if ($multipart) { + $headers = $this->headerSelector->selectHeadersForMultipart( + ['application/json'] + ); + } else { + $headers = $this->headerSelector->selectHeaders( + ['application/json'], + [] + ); + } + + // for model (json/xml) + if (count($formParams) > 0) { + /* @phpstan-ignore-next-line */ + if ($multipart) { + $multipartContents = []; + foreach ($formParams as $formParamName => $formParamValue) { + $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue]; + foreach ($formParamValueItems as $formParamValueItem) { + $multipartContents[] = [ + 'name' => $formParamName, + 'contents' => $formParamValueItem + ]; + } + } + // for HTTP post (form) + $httpBody = new MultipartStream($multipartContents); + + } elseif ($headers['Content-Type'] === 'application/json') { + $httpBody = Utils::jsonEncode($formParams); + + } else { + // for HTTP post (form) + $httpBody = Query::build($formParams); + } + } + + // this endpoint requires API key authentication + $apiKey = $this->config->getApiKeyWithPrefix('x-api-token'); + if ($apiKey !== null) { + $headers['x-api-token'] = $apiKey; + } + // this endpoint requires OAuth (access token) + if ($this->config->getAccessToken() !== null) { + // If access token is expired + if ($this->config->isRefreshPossible() && $this->config->getExpiresAt() <= time()) { + $this->config->refreshToken(); + } + $headers['Authorization'] = 'Bearer ' . $this->config->getAccessToken(); + } + + $defaultHeaders = []; + if ($this->config->getUserAgent()) { + $defaultHeaders['User-Agent'] = $this->config->getUserAgent(); + } + + $headers = array_merge( + $defaultHeaders, + $headerParams, + $headers + ); + + $query = Query::build($queryParams); + return new Request( + 'POST', + $this->config->getHost() . $resourcePath . ($query ? "?{$query}" : ''), + $headers, + $httpBody + ); + } + /** * Operation getProduct * diff --git a/lib/versions/v2/Configuration.php b/lib/versions/v2/Configuration.php index 1a2ebb3..90cca17 100644 --- a/lib/versions/v2/Configuration.php +++ b/lib/versions/v2/Configuration.php @@ -674,7 +674,7 @@ public function updateOAuthRelatedFields(object $oAuthToken): Configuration } if (property_exists($oAuthToken, 'api_domain') && $oAuthToken->api_domain !== null) { - $this->setHost($oAuthToken->api_domain.'/v2'); + $this->setHost($oAuthToken->api_domain.'/api/v2'); } if (is_callable($this->getOAuthTokenUpdateCallback())) { @@ -847,7 +847,7 @@ public function getHostSettings(): array { return [ [ - "url" => "https://api.pipedrive.com/v2", + "url" => "https://api.pipedrive.com/api/v2", "description" => "No description provided", ] ];