diff --git a/.gitignore b/.gitignore index ace3cdf..0e22d4b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ -vendor/ -bin/ +/vendor +/bin composer.lock +composer.phar phpunit.xml .idea .DS_Store @@ -8,3 +9,4 @@ phpunit.xml .buildpath .project .swp +/nbproject diff --git a/README.md b/README.md index 72d2023..994dea7 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,31 @@ -# PHP-клиент для retailCRM API +# retailCRM API PHP client -PHP-клиент для работы с [retailCRM API](http://www.retailcrm.ru/docs/Разработчики/Разработчики#api). +PHP-client for [retailCRM API](http://www.retailcrm.ru/docs/Developers/ApiVersion3). -Рекомендуем обращаться к [документации](http://retailcrm.github.io/api-client-php) по библиотеке, в частности по классу [RetailCrm\ApiClient](http://retailcrm.github.io/api-client-php/class-RetailCrm.ApiClient.html). +Use [API documentation](http://retailcrm.github.io/api-client-php) -## Обязательные требования +## Requirements -* PHP версии 5.3 и выше -* PHP-расширение cURL +* PHP 5.3 and above +* PHP's cURL support -## Установка +## Install -1) Установите [composer](https://getcomposer.org/download/) +1) Get [composer](https://getcomposer.org/download/) -2) Выполните в папке проекта: +2) Run into your project directory: ```bash -composer require retailcrm/api-client-php ~3.0.0 +composer require retailcrm/api-client-php ~3.0.0 --no-dev ``` -В конфиг `composer.json` вашего проекта будет добавлена библиотека `retailcrm/api-client-php`, которая установится в папку `vendor/`. При отсутствии файла конфига или папки с вендорами они будут созданы. - -В случае, если до этого в вашем проекте не использовался `composer`, подключите файл автозагрузки вендоров. Для этого укажите в коде проекта: +If you have not used `composer` before, include autoloader into your project. ```php require 'path/to/vendor/autoload.php'; ``` -## Примеры использования +## Usage -### Получение информации о заказе +### Get order ```php $client = new \RetailCrm\ApiClient( 'https://demo.retailcrm.ru', @@ -38,30 +36,30 @@ $client = new \RetailCrm\ApiClient( try { $response = $client->ordersGet('M-2342'); } catch (\RetailCrm\Exception\CurlException $e) { - echo "Сетевые проблемы. Ошибка подключения к retailCRM: " . $e->getMessage(); + echo "Connection error: " . $e->getMessage(); } if ($response->isSuccessful()) { echo $response->order['totalSumm']; - // или $response['order']['totalSumm']; - // или + // or $response['order']['totalSumm']; + // or // $order = $response->getOrder(); // $order['totalSumm']; } else { echo sprintf( - "Ошибка получения информации о заказа: [Статус HTTP-ответа %s] %s", + "Error: [HTTP-code %s] %s", $response->getStatusCode(), $response->getErrorMsg() ); - - // получить детализацию ошибок + + // error details //if (isset($response['errors'])) { // print_r($response['errors']); //} } ``` -### Создание заказа +### Create order ```php $client = new \RetailCrm\ApiClient( @@ -82,21 +80,21 @@ try { ) )); } catch (\RetailCrm\Exception\CurlException $e) { - echo "Сетевые проблемы. Ошибка подключения к retailCRM: " . $e->getMessage(); + echo "Connection error: " . $e->getMessage(); } if ($response->isSuccessful() && 201 === $response->getStatusCode()) { - echo 'Заказ успешно создан. ID заказа в retailCRM = ' . $response->id; - // или $response['id']; - // или $response->getId(); + echo 'Order successfully created. Order ID into retailCRM = ' . $response->id; + // or $response['id']; + // or $response->getId(); } else { echo sprintf( - "Ошибка создания заказа: [Статус HTTP-ответа %s] %s", + "Error: [HTTP-code %s] %s", $response->getStatusCode(), $response->getErrorMsg() ); - // получить детализацию ошибок + // error details //if (isset($response['errors'])) { // print_r($response['errors']); //} diff --git a/README.ru.md b/README.ru.md new file mode 100644 index 0000000..37ab91e --- /dev/null +++ b/README.ru.md @@ -0,0 +1,104 @@ +# PHP-клиент для retailCRM API + +PHP-клиент для работы с [retailCRM API](http://www.retailcrm.ru/docs/Developers/ApiVersion3). + +Рекомендуем обращаться к [документации](http://retailcrm.github.io/api-client-php) по библиотеке, в частности по классу [RetailCrm\ApiClient](http://retailcrm.github.io/api-client-php/class-RetailCrm.ApiClient.html). + +## Обязательные требования + +* PHP версии 5.3 и выше +* PHP-расширение cURL + +## Установка + +1) Установите [composer](https://getcomposer.org/download/) + +2) Выполните в папке проекта: +```bash +composer require retailcrm/api-client-php ~3.0.0 --no-dev +``` + +В конфиг `composer.json` вашего проекта будет добавлена библиотека `retailcrm/api-client-php`, которая установится в папку `vendor/`. При отсутствии файла конфига или папки с вендорами они будут созданы. + +В случае, если до этого в вашем проекте не использовался `composer`, подключите файл автозагрузки вендоров. Для этого укажите в коде проекта: +```php +require 'path/to/vendor/autoload.php'; +``` + +## Примеры использования + +### Получение информации о заказе +```php +$client = new \RetailCrm\ApiClient( + 'https://demo.retailcrm.ru', + 'T9DMPvuNt7FQJMszHUdG8Fkt6xHsqngH' +); + + +try { + $response = $client->ordersGet('M-2342'); +} catch (\RetailCrm\Exception\CurlException $e) { + echo "Сетевые проблемы. Ошибка подключения к retailCRM: " . $e->getMessage(); +} + +if ($response->isSuccessful()) { + echo $response->order['totalSumm']; + // или $response['order']['totalSumm']; + // или + // $order = $response->getOrder(); + // $order['totalSumm']; +} else { + echo sprintf( + "Ошибка получения информации о заказа: [Статус HTTP-ответа %s] %s", + $response->getStatusCode(), + $response->getErrorMsg() + ); + + // получить детализацию ошибок + //if (isset($response['errors'])) { + // print_r($response['errors']); + //} +} +``` + +### Создание заказа +```php + +$client = new \RetailCrm\ApiClient( + 'https://demo.retailcrm.ru', + 'T9DMPvuNt7FQJMszHUdG8Fkt6xHsqngH' +); + +try { + $response = $client->ordersCreate(array( + 'externalId' => 'some-shop-order-id', + 'firstName' => 'Vasily', + 'lastName' => 'Pupkin', + 'items' => array( + //... + ), + 'delivery' => array( + 'code' => 'russian-post', + ) + )); +} catch (\RetailCrm\Exception\CurlException $e) { + echo "Сетевые проблемы. Ошибка подключения к retailCRM: " . $e->getMessage(); +} + +if ($response->isSuccessful() && 201 === $response->getStatusCode()) { + echo 'Заказ успешно создан. ID заказа в retailCRM = ' . $response->id; + // или $response['id']; + // или $response->getId(); +} else { + echo sprintf( + "Ошибка создания заказа: [Статус HTTP-ответа %s] %s", + $response->getStatusCode(), + $response->getErrorMsg() + ); + + // получить детализацию ошибок + //if (isset($response['errors'])) { + // print_r($response['errors']); + //} +} +``` diff --git a/composer.json b/composer.json index 8280092..999437a 100644 --- a/composer.json +++ b/composer.json @@ -4,6 +4,7 @@ "type": "library", "keywords": ["API", "retailCRM", "REST"], "homepage": "http://www.retailcrm.ru/", + "license": "MIT", "authors": [ { "name": "retailCRM", @@ -15,12 +16,14 @@ "ext-curl": "*" }, "require-dev": { - "phpunit/phpunit": "3.7.*", - "phpmd/phpmd": "2.1.*", + "phpunit/phpunit": "5.2.*",, + "phpunit/php-code-coverage": "3.3.0", + "phpunit/php-invoker": "1.1.4" + "phpmd/phpmd": "2.4.*", "sebastian/phpcpd": "2.0.*", "sebastian/phpdcd": "1.0.*", - "squizlabs/php_codesniffer": "dev-master", - "apigen/apigen": "~4.0@dev" + "squizlabs/php_codesniffer": "2.5.*", + "apigen/apigen": "4.1.*" }, "support": { "email": "support@intarocrm.ru" diff --git a/lib/RetailCrm/ApiClient.php b/lib/RetailCrm/ApiClient.php index e670b31..1adfe30 100644 --- a/lib/RetailCrm/ApiClient.php +++ b/lib/RetailCrm/ApiClient.php @@ -6,10 +6,19 @@ use RetailCrm\Http\Client; use RetailCrm\Response\ApiResponse; /** - * retailCRM API client class + * PHP version 5.3 + * + * API client class + * + * @category RetailCrm + * @package RetailCrm + * @author RetailCrm + * @license https://opensource.org/licenses/MIT MIT License + * @link http://www.retailcrm.ru/docs/Developers/ApiVersion3 */ class ApiClient { + const VERSION = 'v3'; protected $client; @@ -22,14 +31,17 @@ class ApiClient /** * Client creating * - * @param string $url - * @param string $apiKey - * @param string $siteCode + * @param string $url api url + * @param string $apiKey api key + * @param string $site site code + * + * @throws \InvalidArgumentException + * * @return mixed */ public function __construct($url, $apiKey, $site = null) { - if ('/' != substr($url, strlen($url) - 1, 1)) { + if ('/' !== substr($url, strlen($url) - 1, 1)) { $url .= '/'; } @@ -40,95 +52,106 @@ class ApiClient } /** - * Create a order + * Returns filtered orders list + * + * @param array $filter (default: array()) + * @param int $page (default: null) + * @param int $limit (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException * - * @param array $order - * @param string $site (default: null) * @return ApiResponse */ - public function ordersCreate(array $order, $site = null) + public function ordersList(array $filter = array(), $page = null, $limit = null) { - if (!sizeof($order)) { - throw new \InvalidArgumentException('Parameter `order` must contains a data'); + $parameters = array(); + + if (count($filter)) { + $parameters['filter'] = $filter; } - - return $this->client->makeRequest("/orders/create", Client::METHOD_POST, $this->fillSite($site, array( - 'order' => json_encode($order) - ))); - } - - /** - * Edit a order - * - * @param array $order - * @param string $site (default: null) - * @return ApiResponse - */ - public function ordersEdit(array $order, $by = 'externalId', $site = null) - { - if (!sizeof($order)) { - throw new \InvalidArgumentException('Parameter `order` must contains a data'); + if (null !== $page) { + $parameters['page'] = (int) $page; } - - $this->checkIdParameter($by); - - if (!isset($order[$by])) { - throw new \InvalidArgumentException(sprintf('Order array must contain the "%s" parameter.', $by)); + if (null !== $limit) { + $parameters['limit'] = (int) $limit; } return $this->client->makeRequest( - "/orders/" . $order[$by] . "/edit", - Client::METHOD_POST, - $this->fillSite($site, array( - 'order' => json_encode($order), - 'by' => $by, - )) + '/orders', + Client::METHOD_GET, + $parameters ); } /** - * Upload array of the orders + * Create a order + * + * @param array $order order data + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException * - * @param array $orders - * @param string $site (default: null) * @return ApiResponse */ - public function ordersUpload(array $orders, $site = null) + public function ordersCreate(array $order, $site = null) { - if (!sizeof($orders)) { - throw new \InvalidArgumentException('Parameter `orders` must contains array of the orders'); + if (!count($order)) { + throw new \InvalidArgumentException( + 'Parameter `order` must contains a data' + ); } - return $this->client->makeRequest("/orders/upload", Client::METHOD_POST, $this->fillSite($site, array( - 'orders' => json_encode($orders), - ))); + return $this->client->makeRequest( + '/orders/create', + Client::METHOD_POST, + $this->fillSite($site, array('order' => json_encode($order))) + ); } /** - * Get order by id or externalId + * Save order IDs' (id and externalId) association in the CRM + * + * @param array $ids order identificators + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException * - * @param string $id - * @param string $by (default: 'externalId') - * @param string $site (default: null) * @return ApiResponse */ - public function ordersGet($id, $by = 'externalId', $site = null) + public function ordersFixExternalIds(array $ids) { - $this->checkIdParameter($by); + if (! count($ids)) { + throw new \InvalidArgumentException( + 'Method parameter must contains at least one IDs pair' + ); + } - return $this->client->makeRequest("/orders/$id", Client::METHOD_GET, $this->fillSite($site, array( - 'by' => $by - ))); + return $this->client->makeRequest( + '/orders/fix-external-ids', + Client::METHOD_POST, + array('orders' => json_encode($ids) + ) + ); } /** * Returns a orders history * - * @param \DateTime $startDate (default: null) - * @param \DateTime $endDate (default: null) - * @param int $limit (default: 100) - * @param int $offset (default: 0) - * @param bool $skipMyChanges (default: true) + * @param \DateTime $startDate (default: null) + * @param \DateTime $endDate (default: null) + * @param int $limit (default: 100) + * @param int $offset (default: 0) + * @param bool $skipMyChanges (default: true) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * * @return ApiResponse */ public function ordersHistory( @@ -156,85 +179,156 @@ class ApiClient $parameters['skipMyChanges'] = (bool) $skipMyChanges; } - return $this->client->makeRequest('/orders/history', Client::METHOD_GET, $parameters); - } - - /** - * Returns filtered orders list - * - * @param array $filter (default: array()) - * @param int $page (default: null) - * @param int $limit (default: null) - * @return ApiResponse - */ - public function ordersList(array $filter = array(), $page = null, $limit = null) - { - $parameters = array(); - - if (sizeof($filter)) { - $parameters['filter'] = $filter; - } - if (null !== $page) { - $parameters['page'] = (int) $page; - } - if (null !== $limit) { - $parameters['limit'] = (int) $limit; - } - - return $this->client->makeRequest('/orders', Client::METHOD_GET, $parameters); + return $this->client->makeRequest( + '/orders/history', + Client::METHOD_GET, + $parameters + ); } /** * Returns statuses of the orders * - * @param array $ids (default: array()) - * @param array $externalIds (default: array()) + * @param array $ids (default: array()) + * @param array $externalIds (default: array()) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * * @return ApiResponse */ - public function ordersStatuses(array $ids = array(), array $externalIds = array()) - { + public function ordersStatuses( + array $ids = array(), + array $externalIds = array() + ) { $parameters = array(); - if (sizeof($ids)) { + if (count($ids)) { $parameters['ids'] = $ids; } - if (sizeof($externalIds)) { + if (count($externalIds)) { $parameters['externalIds'] = $externalIds; } - return $this->client->makeRequest('/orders/statuses', Client::METHOD_GET, $parameters); + return $this->client->makeRequest( + '/orders/statuses', + Client::METHOD_GET, + $parameters + ); } /** - * Save order IDs' (id and externalId) association in the CRM + * Upload array of the orders + * + * @param array $orders array of orders + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException * - * @param array $ids * @return ApiResponse */ - public function ordersFixExternalIds(array $ids) + public function ordersUpload(array $orders, $site = null) { - if (!sizeof($ids)) { - throw new \InvalidArgumentException('Method parameter must contains at least one IDs pair'); + if (!count($orders)) { + throw new \InvalidArgumentException( + 'Parameter `orders` must contains array of the orders' + ); } - return $this->client->makeRequest("/orders/fix-external-ids", Client::METHOD_POST, array( - 'orders' => json_encode($ids), - )); + return $this->client->makeRequest( + '/orders/upload', + Client::METHOD_POST, + $this->fillSite($site, array('orders' => json_encode($orders))) + ); } /** - * Get orders assembly history + * Get order by id or externalId + * + * @param string $id order identificator + * @param string $by (default: 'externalId') + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException * - * @param array $filter (default: array()) - * @param int $page (default: null) - * @param int $limit (default: null) * @return ApiResponse */ - public function ordersPacksHistory(array $filter = array(), $page = null, $limit = null) + public function ordersGet($id, $by = 'externalId', $site = null) { + $this->checkIdParameter($by); + + return $this->client->makeRequest( + "/orders/$id", + Client::METHOD_GET, + $this->fillSite($site, array('by' => $by)) + ); + } + + /** + * Edit a order + * + * @param array $order order data + * @param string $by (default: 'externalId') + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function ordersEdit(array $order, $by = 'externalId', $site = null) + { + if (!count($order)) { + throw new \InvalidArgumentException( + 'Parameter `order` must contains a data' + ); + } + + $this->checkIdParameter($by); + + if (!array_key_exists($by, $order)) { + throw new \InvalidArgumentException( + sprintf('Order array must contain the "%s" parameter.', $by) + ); + } + + return $this->client->makeRequest( + sprintf('/orders/%s/edit', $order[$by]), + Client::METHOD_POST, + $this->fillSite( + $site, + array('order' => json_encode($order), 'by' => $by) + ) + ); + } + + /** + * Returns filtered customers list + * + * @param array $filter (default: array()) + * @param int $page (default: null) + * @param int $limit (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function customersList( + array $filter = array(), + $page = null, + $limit = null + ) { $parameters = array(); - if (sizeof($filter)) { + if (count($filter)) { $parameters['filter'] = $filter; } if (null !== $page) { @@ -244,108 +338,177 @@ class ApiClient $parameters['limit'] = (int) $limit; } - return $this->client->makeRequest('/orders/packs/history', Client::METHOD_GET, $parameters); + return $this->client->makeRequest( + '/customers', + Client::METHOD_GET, + $parameters + ); } /** * Create a customer * - * @param array $customer - * @param string $site (default: null) + * @param array $customer customer data + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * * @return ApiResponse */ public function customersCreate(array $customer, $site = null) { - if (!sizeof($customer)) { - throw new \InvalidArgumentException('Parameter `customer` must contains a data'); - } - - return $this->client->makeRequest("/customers/create", Client::METHOD_POST, $this->fillSite($site, array( - 'customer' => json_encode($customer) - ))); - } - - /** - * Edit a customer - * - * @param array $customer - * @param string $by (default: 'externalId') - * @param string $site (default: null) - * @return ApiResponse - */ - public function customersEdit(array $customer, $by = 'externalId', $site = null) - { - if (!sizeof($customer)) { - throw new \InvalidArgumentException('Parameter `customer` must contains a data'); - } - - $this->checkIdParameter($by); - - if (!isset($customer[$by])) { - throw new \InvalidArgumentException(sprintf('Customer array must contain the "%s" parameter.', $by)); + if (! count($customer)) { + throw new \InvalidArgumentException( + 'Parameter `customer` must contains a data' + ); } return $this->client->makeRequest( - "/customers/" . $customer[$by] . "/edit", + '/customers/create', Client::METHOD_POST, - $this->fillSite( - $site, - array( - 'customer' => json_encode($customer), - 'by' => $by - ) - ) + $this->fillSite($site, array('customer' => json_encode($customer))) + ); + } + + /** + * Save customer IDs' (id and externalId) association in the CRM + * + * @param array $ids ids mapping + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function customersFixExternalIds(array $ids) + { + if (! count($ids)) { + throw new \InvalidArgumentException( + 'Method parameter must contains at least one IDs pair' + ); + } + + return $this->client->makeRequest( + '/customers/fix-external-ids', + Client::METHOD_POST, + array('customers' => json_encode($ids)) ); } /** * Upload array of the customers * - * @param array $customers - * @param string $site (default: null) + * @param array $customers array of customers + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * * @return ApiResponse */ public function customersUpload(array $customers, $site = null) { - if (!sizeof($customers)) { - throw new \InvalidArgumentException('Parameter `customers` must contains array of the customers'); + if (! count($customers)) { + throw new \InvalidArgumentException( + 'Parameter `customers` must contains array of the customers' + ); } - return $this->client->makeRequest("/customers/upload", Client::METHOD_POST, $this->fillSite($site, array( - 'customers' => json_encode($customers), - ))); + return $this->client->makeRequest( + '/customers/upload', + Client::METHOD_POST, + $this->fillSite($site, array('customers' => json_encode($customers))) + ); } /** * Get customer by id or externalId * - * @param string $id - * @param string $by (default: 'externalId') - * @param string $site (default: null) + * @param string $id customer identificator + * @param string $by (default: 'externalId') + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * * @return ApiResponse */ public function customersGet($id, $by = 'externalId', $site = null) { $this->checkIdParameter($by); - return $this->client->makeRequest("/customers/$id", Client::METHOD_GET, $this->fillSite($site, array( - 'by' => $by - ))); + return $this->client->makeRequest( + "/customers/$id", + Client::METHOD_GET, + $this->fillSite($site, array('by' => $by)) + ); } /** - * Returns filtered customers list + * Edit a customer + * + * @param array $customer customer data + * @param string $by (default: 'externalId') + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException * - * @param array $filter (default: array()) - * @param int $page (default: null) - * @param int $limit (default: null) * @return ApiResponse */ - public function customersList(array $filter = array(), $page = null, $limit = null) + public function customersEdit(array $customer, $by = 'externalId', $site = null) { + if (!count($customer)) { + throw new \InvalidArgumentException( + 'Parameter `customer` must contains a data' + ); + } + + $this->checkIdParameter($by); + + if (!array_key_exists($by, $customer)) { + throw new \InvalidArgumentException( + sprintf('Customer array must contain the "%s" parameter.', $by) + ); + } + + return $this->client->makeRequest( + sprintf('/customers/%s/edit', $customer[$by]), + Client::METHOD_POST, + $this->fillSite( + $site, + array('customer' => json_encode($customer), 'by' => $by) + ) + ); + } + + /** + * Get orders assembly list + * + * @param array $filter (default: array()) + * @param int $page (default: null) + * @param int $limit (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function ordersPacksList( + array $filter = array(), + $page = null, + $limit = null + ) { $parameters = array(); - if (sizeof($filter)) { + if (count($filter)) { $parameters['filter'] = $filter; } if (null !== $page) { @@ -355,40 +518,171 @@ class ApiClient $parameters['limit'] = (int) $limit; } - return $this->client->makeRequest('/customers', Client::METHOD_GET, $parameters); + return $this->client->makeRequest( + '/orders/packs', + Client::METHOD_GET, + $parameters + ); } /** - * Save customer IDs' (id and externalId) association in the CRM + * Create orders assembly + * + * @param array $pack pack data + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException * - * @param array $ids * @return ApiResponse */ - public function customersFixExternalIds(array $ids) + public function ordersPacksCreate(array $pack, $site = null) { - if (!sizeof($ids)) { - throw new \InvalidArgumentException('Method parameter must contains at least one IDs pair'); + if (!count($pack)) { + throw new \InvalidArgumentException( + 'Parameter `pack` must contains a data' + ); } - return $this->client->makeRequest("/customers/fix-external-ids", Client::METHOD_POST, array( - 'customers' => json_encode($ids), - )); + return $this->client->makeRequest( + '/orders/packs/create', + Client::METHOD_POST, + $this->fillSite($site, array('pack' => json_encode($pack))) + ); + } + + /** + * Get orders assembly history + * + * @param array $filter (default: array()) + * @param int $page (default: null) + * @param int $limit (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function ordersPacksHistory( + array $filter = array(), + $page = null, + $limit = null + ) { + $parameters = array(); + + if (count($filter)) { + $parameters['filter'] = $filter; + } + if (null !== $page) { + $parameters['page'] = (int) $page; + } + if (null !== $limit) { + $parameters['limit'] = (int) $limit; + } + + return $this->client->makeRequest( + '/orders/packs/history', + Client::METHOD_GET, + $parameters + ); + } + + /** + * Get orders assembly by id + * + * @param string $id pack identificator + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function ordersPacksGet($id) + { + if (empty($id)) { + throw new \InvalidArgumentException('Parameter `id` must be set'); + } + + return $this->client->makeRequest( + "/orders/packs/$id", + Client::METHOD_GET + ); + } + + /** + * Delete orders assembly by id + * + * @param string $id pack identificator + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function ordersPacksDelete($id) + { + if (empty($id)) { + throw new \InvalidArgumentException('Parameter `id` must be set'); + } + + return $this->client->makeRequest( + sprintf('/orders/packs/%s/delete', $id), + Client::METHOD_POST + ); + } + + /** + * Edit orders assembly + * + * @param array $pack pack data + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function ordersPacksEdit(array $pack, $site = null) + { + if (!count($pack) || empty($pack['id'])) { + throw new \InvalidArgumentException( + 'Parameter `pack` must contains a data & pack `id` must be set' + ); + } + + return $this->client->makeRequest( + sprintf('/orders/packs/%s/edit', $pack['id']), + Client::METHOD_POST, + $this->fillSite($site, array('pack' => json_encode($pack))) + ); } /** * Get purchace prices & stock balance * - * @param array $filter (default: array()) - * @param int $page (default: null) - * @param int $limit (default: null) - * @param string $site (default: null) + * @param array $filter (default: array()) + * @param int $page (default: null) + * @param int $limit (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * * @return ApiResponse */ - public function storeInventories(array $filter = array(), $page = null, $limit = null, $site = null) - { + public function storeInventories( + array $filter = array(), + $page = null, + $limit = null + ) { $parameters = array(); - if (sizeof($filter)) { + if (count($filter)) { $parameters['filter'] = $filter; } if (null !== $page) { @@ -398,147 +692,114 @@ class ApiClient $parameters['limit'] = (int) $limit; } - return $this->client->makeRequest('/store/inventories', Client::METHOD_GET, $this->fillSite($site, $parameters)); + return $this->client->makeRequest( + '/store/inventories', + Client::METHOD_GET, + $parameters + ); } /** * Upload store inventories * - * @param array $offers - * @param string $site (default: null) + * @param array $offers offers data + * @param string $site (default: null) + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * * @return ApiResponse */ public function storeInventoriesUpload(array $offers, $site = null) { - if (!sizeof($offers)) { - throw new \InvalidArgumentException('Parameter `offers` must contains array of the offers'); + if (!count($offers)) { + throw new \InvalidArgumentException( + 'Parameter `offers` must contains array of the offers' + ); } return $this->client->makeRequest( - "/store/inventories/upload", + '/store/inventories/upload', Client::METHOD_POST, $this->fillSite($site, array('offers' => json_encode($offers))) ); } + /** + * Returns available county list + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function countriesList() + { + return $this->client->makeRequest( + '/reference/countries', + Client::METHOD_GET + ); + } + /** * Returns deliveryServices list * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * * @return ApiResponse */ public function deliveryServicesList() { - return $this->client->makeRequest('/reference/delivery-services', Client::METHOD_GET); - } - - /** - * Returns deliveryTypes list - * - * @return ApiResponse - */ - public function deliveryTypesList() - { - return $this->client->makeRequest('/reference/delivery-types', Client::METHOD_GET); - } - - /** - * Returns orderMethods list - * - * @return ApiResponse - */ - public function orderMethodsList() - { - return $this->client->makeRequest('/reference/order-methods', Client::METHOD_GET); - } - - /** - * Returns orderTypes list - * - * @return ApiResponse - */ - public function orderTypesList() - { - return $this->client->makeRequest('/reference/order-types', Client::METHOD_GET); - } - - /** - * Returns paymentStatuses list - * - * @return ApiResponse - */ - public function paymentStatusesList() - { - return $this->client->makeRequest('/reference/payment-statuses', Client::METHOD_GET); - } - - /** - * Returns paymentTypes list - * - * @return ApiResponse - */ - public function paymentTypesList() - { - return $this->client->makeRequest('/reference/payment-types', Client::METHOD_GET); - } - - /** - * Returns productStatuses list - * - * @return ApiResponse - */ - public function productStatusesList() - { - return $this->client->makeRequest('/reference/product-statuses', Client::METHOD_GET); - } - - /** - * Returns statusGroups list - * - * @return ApiResponse - */ - public function statusGroupsList() - { - return $this->client->makeRequest('/reference/status-groups', Client::METHOD_GET); - } - - /** - * Returns statuses list - * - * @return ApiResponse - */ - public function statusesList() - { - return $this->client->makeRequest('/reference/statuses', Client::METHOD_GET); - } - - /** - * Returns sites list - * - * @return ApiResponse - */ - public function sitesList() - { - return $this->client->makeRequest('/reference/sites', Client::METHOD_GET); + return $this->client->makeRequest( + '/reference/delivery-services', + Client::METHOD_GET + ); } /** * Edit deliveryService * * @param array $data delivery service data + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * * @return ApiResponse */ public function deliveryServicesEdit(array $data) { - if (!isset($data['code'])) { - throw new \InvalidArgumentException('Data must contain "code" parameter.'); + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); } return $this->client->makeRequest( - '/reference/delivery-services/' . $data['code'] . '/edit', + sprintf('/reference/delivery-services/%s/edit', $data['code']), Client::METHOD_POST, - array( - 'deliveryService' => json_encode($data) - ) + array('deliveryService' => json_encode($data)) + ); + } + + /** + * Returns deliveryTypes list + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function deliveryTypesList() + { + return $this->client->makeRequest( + '/reference/delivery-types', + Client::METHOD_GET ); } @@ -546,20 +807,42 @@ class ApiClient * Edit deliveryType * * @param array $data delivery type data + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * * @return ApiResponse */ public function deliveryTypesEdit(array $data) { - if (!isset($data['code'])) { - throw new \InvalidArgumentException('Data must contain "code" parameter.'); + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); } return $this->client->makeRequest( - '/reference/delivery-types/' . $data['code'] . '/edit', + sprintf('/reference/delivery-types/%s/edit', $data['code']), Client::METHOD_POST, - array( - 'deliveryType' => json_encode($data) - ) + array('deliveryType' => json_encode($data)) + ); + } + + /** + * Returns orderMethods list + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function orderMethodsList() + { + return $this->client->makeRequest( + '/reference/order-methods', + Client::METHOD_GET ); } @@ -567,20 +850,42 @@ class ApiClient * Edit orderMethod * * @param array $data order method data + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * * @return ApiResponse */ public function orderMethodsEdit(array $data) { - if (!isset($data['code'])) { - throw new \InvalidArgumentException('Data must contain "code" parameter.'); + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); } return $this->client->makeRequest( - '/reference/order-methods/' . $data['code'] . '/edit', + sprintf('/reference/order-methods/%s/edit', $data['code']), Client::METHOD_POST, - array( - 'orderMethod' => json_encode($data) - ) + array('orderMethod' => json_encode($data)) + ); + } + + /** + * Returns orderTypes list + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function orderTypesList() + { + return $this->client->makeRequest( + '/reference/order-types', + Client::METHOD_GET ); } @@ -588,20 +893,42 @@ class ApiClient * Edit orderType * * @param array $data order type data + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * * @return ApiResponse */ public function orderTypesEdit(array $data) { - if (!isset($data['code'])) { - throw new \InvalidArgumentException('Data must contain "code" parameter.'); + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); } return $this->client->makeRequest( - '/reference/order-types/' . $data['code'] . '/edit', + sprintf('/reference/order-types/%s/edit', $data['code']), Client::METHOD_POST, - array( - 'orderType' => json_encode($data) - ) + array('orderType' => json_encode($data)) + ); + } + + /** + * Returns paymentStatuses list + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function paymentStatusesList() + { + return $this->client->makeRequest( + '/reference/payment-statuses', + Client::METHOD_GET ); } @@ -609,20 +936,42 @@ class ApiClient * Edit paymentStatus * * @param array $data payment status data + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * * @return ApiResponse */ public function paymentStatusesEdit(array $data) { - if (!isset($data['code'])) { - throw new \InvalidArgumentException('Data must contain "code" parameter.'); + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); } return $this->client->makeRequest( - '/reference/payment-statuses/' . $data['code'] . '/edit', + sprintf('/reference/payment-statuses/%s/edit', $data['code']), Client::METHOD_POST, - array( - 'paymentStatus' => json_encode($data) - ) + array('paymentStatus' => json_encode($data)) + ); + } + + /** + * Returns paymentTypes list + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function paymentTypesList() + { + return $this->client->makeRequest( + '/reference/payment-types', + Client::METHOD_GET ); } @@ -630,20 +979,42 @@ class ApiClient * Edit paymentType * * @param array $data payment type data + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * * @return ApiResponse */ public function paymentTypesEdit(array $data) { - if (!isset($data['code'])) { - throw new \InvalidArgumentException('Data must contain "code" parameter.'); + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); } return $this->client->makeRequest( - '/reference/payment-types/' . $data['code'] . '/edit', + sprintf('/reference/payment-types/%s/edit', $data['code']), Client::METHOD_POST, - array( - 'paymentType' => json_encode($data) - ) + array('paymentType' => json_encode($data)) + ); + } + + /** + * Returns productStatuses list + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function productStatusesList() + { + return $this->client->makeRequest( + '/reference/product-statuses', + Client::METHOD_GET ); } @@ -651,41 +1022,42 @@ class ApiClient * Edit productStatus * * @param array $data product status data + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * * @return ApiResponse */ public function productStatusesEdit(array $data) { - if (!isset($data['code'])) { - throw new \InvalidArgumentException('Data must contain "code" parameter.'); + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); } return $this->client->makeRequest( - '/reference/product-statuses/' . $data['code'] . '/edit', + sprintf('/reference/product-statuses/%s/edit', $data['code']), Client::METHOD_POST, - array( - 'productStatus' => json_encode($data) - ) + array('productStatus' => json_encode($data)) ); } /** - * Edit order status + * Returns sites list + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException * - * @param array $data status data * @return ApiResponse */ - public function statusesEdit(array $data) + public function sitesList() { - if (!isset($data['code'])) { - throw new \InvalidArgumentException('Data must contain "code" parameter.'); - } - return $this->client->makeRequest( - '/reference/statuses/' . $data['code'] . '/edit', - Client::METHOD_POST, - array( - 'status' => json_encode($data) - ) + '/reference/sites', + Client::METHOD_GET ); } @@ -693,31 +1065,248 @@ class ApiClient * Edit site * * @param array $data site data + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * * @return ApiResponse */ public function sitesEdit(array $data) { - if (!isset($data['code'])) { - throw new \InvalidArgumentException('Data must contain "code" parameter.'); + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); } return $this->client->makeRequest( - '/reference/sites/' . $data['code'] . '/edit', + sprintf('/reference/sites/%s/edit', $data['code']), Client::METHOD_POST, - array( - 'site' => json_encode($data) - ) + array('site' => json_encode($data)) + ); + } + + /** + * Returns statusGroups list + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function statusGroupsList() + { + return $this->client->makeRequest( + '/reference/status-groups', + Client::METHOD_GET + ); + } + + /** + * Returns statuses list + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function statusesList() + { + return $this->client->makeRequest( + '/reference/statuses', + Client::METHOD_GET + ); + } + + /** + * Edit order status + * + * @param array $data status data + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function statusesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/statuses/%s/edit', $data['code']), + Client::METHOD_POST, + array('status' => json_encode($data)) + ); + } + + /** + * Returns stores list + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function storesList() + { + return $this->client->makeRequest( + '/reference/stores', + Client::METHOD_GET + ); + } + + /** + * Edit store + * + * @param array $data site data + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function storesEdit(array $data) + { + if (!array_key_exists('code', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "code" parameter.' + ); + } + + if (!array_key_exists('name', $data)) { + throw new \InvalidArgumentException( + 'Data must contain "name" parameter.' + ); + } + + return $this->client->makeRequest( + sprintf('/reference/stores/%s/edit', $data['code']), + Client::METHOD_POST, + array('store' => json_encode($data)) ); } /** * Update CRM basic statistic * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * * @return ApiResponse */ public function statisticUpdate() { - return $this->client->makeRequest('/statistic/update', Client::METHOD_GET); + return $this->client->makeRequest( + '/statistic/update', + Client::METHOD_GET + ); + } + + /** + * Call event + * + * @param string $phone phone number + * @param string $type call type + * @param string $code additional phone code + * @param string $status call status + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function telephonyCallEvent($phone, $type, $code, $status) + { + if (!isset($phone)) { + throw new \InvalidArgumentException('Phone number must be set'); + } + + $parameters['phone'] = $phone; + + if (!isset($type)) { + throw new \InvalidArgumentException('Type must be set (in|out|hangup)'); + } + + $parameters['type'] = $type; + + if (!isset($code)) { + throw new \InvalidArgumentException('Code must be set'); + } + + $parameters['code'] = $code; + $parameters['hangupStatus'] = $status; + + return $this->client->makeRequest( + '/telephony/call/event', + Client::METHOD_POST, + $parameters + ); + } + + /** + * Upload calls + * + * @param array $calls calls data + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function telephonyCallsUpload(array $calls) + { + if (!count($calls)) { + throw new \InvalidArgumentException( + 'Parameter `calls` must contains array of the calls' + ); + } + + return $this->client->makeRequest( + '/telephony/calls/upload', + Client::METHOD_POST, + array('calls' => json_encode($calls)) + ); + } + + /** + * Get call manager + * + * @param string $phone phone number + * @param bool $details detailed information + * + * @throws \InvalidArgumentException + * @throws \RetailCrm\Exception\CurlException + * @throws \RetailCrm\Exception\InvalidJsonException + * + * @return ApiResponse + */ + public function telephonyCallManager($phone, $details) + { + if (!isset($phone)) { + throw new \InvalidArgumentException('Phone number must be set'); + } + + $parameters['phone'] = $phone; + $parameters['details'] = isset($details) ? $details : 0; + + return $this->client->makeRequest( + '/telephony/manager', + Client::METHOD_GET, + $parameters + ); } /** @@ -733,7 +1322,8 @@ class ApiClient /** * Set site * - * @param string $site + * @param string $site site code + * * @return void */ public function setSite($site) @@ -744,18 +1334,27 @@ class ApiClient /** * Check ID parameter * - * @param string $by + * @param string $by identify by + * + * @throws \InvalidArgumentException + * * @return bool */ protected function checkIdParameter($by) { - $allowedForBy = array('externalId', 'id'); - if (!in_array($by, $allowedForBy)) { - throw new \InvalidArgumentException(sprintf( - 'Value "%s" for parameter "by" is not valid. Allowed values are %s.', - $by, - implode(', ', $allowedForBy) - )); + $allowedForBy = array( + 'externalId', + 'id' + ); + + if (!in_array($by, $allowedForBy, false)) { + throw new \InvalidArgumentException( + sprintf( + 'Value "%s" for parameter "by" is not valid. Allowed values are %s.', + $by, + implode(', ', $allowedForBy) + ) + ); } return true; @@ -764,8 +1363,9 @@ class ApiClient /** * Fill params by site value * - * @param string $site - * @param array $params + * @param string $site site code + * @param array $params input parameters + * * @return array */ protected function fillSite($site, array $params) diff --git a/lib/RetailCrm/Exception/CurlException.php b/lib/RetailCrm/Exception/CurlException.php index 08a0924..d3b8e1a 100644 --- a/lib/RetailCrm/Exception/CurlException.php +++ b/lib/RetailCrm/Exception/CurlException.php @@ -2,6 +2,17 @@ namespace RetailCrm\Exception; +/** + * PHP version 5.3 + * + * Class CurlException + * + * @category RetailCrm + * @package RetailCrm + * @author RetailCrm + * @license https://opensource.org/licenses/MIT MIT License + * @link http://www.retailcrm.ru/docs/Developers/ApiVersion3 + */ class CurlException extends \RuntimeException { } diff --git a/lib/RetailCrm/Exception/InvalidJsonException.php b/lib/RetailCrm/Exception/InvalidJsonException.php index 979d12e..1a06536 100644 --- a/lib/RetailCrm/Exception/InvalidJsonException.php +++ b/lib/RetailCrm/Exception/InvalidJsonException.php @@ -2,6 +2,17 @@ namespace RetailCrm\Exception; +/** + * PHP version 5.3 + * + * Class InvalidJsonException + * + * @category RetailCrm + * @package RetailCrm + * @author RetailCrm + * @license https://opensource.org/licenses/MIT MIT License + * @link http://www.retailcrm.ru/docs/Developers/ApiVersion3 + */ class InvalidJsonException extends \DomainException { } diff --git a/lib/RetailCrm/Http/Client.php b/lib/RetailCrm/Http/Client.php index 69ce1fb..eafb079 100644 --- a/lib/RetailCrm/Http/Client.php +++ b/lib/RetailCrm/Http/Client.php @@ -3,10 +3,19 @@ namespace RetailCrm\Http; use RetailCrm\Exception\CurlException; +use RetailCrm\Exception\InvalidJsonException; use RetailCrm\Response\ApiResponse; /** + * PHP version 5.3 + * * HTTP client + * + * @category RetailCrm + * @package RetailCrm + * @author RetailCrm + * @license https://opensource.org/licenses/MIT MIT License + * @link http://www.retailcrm.ru/docs/Developers/ApiVersion3 */ class Client { @@ -17,74 +26,105 @@ class Client protected $defaultParameters; protected $retry; + /** + * Client constructor. + * + * @param string $url api url + * @param array $defaultParameters array of parameters + * + * @throws \InvalidArgumentException + */ public function __construct($url, array $defaultParameters = array()) { if (false === stripos($url, 'https://')) { - throw new \InvalidArgumentException('API schema requires HTTPS protocol'); + throw new \InvalidArgumentException( + 'API schema requires HTTPS protocol' + ); } $this->url = $url; $this->defaultParameters = $defaultParameters; $this->retry = 0; + $this->curlErrors = array( + CURLE_COULDNT_RESOLVE_PROXY, + CURLE_COULDNT_RESOLVE_HOST, + CURLE_COULDNT_CONNECT, + CURLE_OPERATION_TIMEOUTED, + CURLE_HTTP_POST_ERROR, + CURLE_SSL_CONNECT_ERROR, + CURLE_SEND_ERROR, + CURLE_RECV_ERROR + ); } /** * Make HTTP request * - * @param string $path - * @param string $method (default: 'GET') - * @param array $parameters (default: array()) - * @param int $timeout - * @param bool $verify - * @param bool $debug + * @param string $path request url + * @param string $method (default: 'GET') + * @param array $parameters (default: array()) + * + * @SuppressWarnings(PHPMD.ExcessiveParameterList) + * + * @throws \InvalidArgumentException + * @throws CurlException + * @throws InvalidJsonException + * * @return ApiResponse */ public function makeRequest( $path, $method, - array $parameters = array(), - $timeout = 30, - $verify = false, - $debug = false + array $parameters = array() ) { $allowedMethods = array(self::METHOD_GET, self::METHOD_POST); - if (!in_array($method, $allowedMethods)) { - throw new \InvalidArgumentException(sprintf( - 'Method "%s" is not valid. Allowed methods are %s', - $method, - implode(', ', $allowedMethods) - )); + + if (!in_array($method, $allowedMethods, false)) { + throw new \InvalidArgumentException( + sprintf( + 'Method "%s" is not valid. Allowed methods are %s', + $method, + implode(', ', $allowedMethods) + ) + ); } $parameters = array_merge($this->defaultParameters, $parameters); - $path = $this->url . $path; + $url = $this->url . $path; - if (self::METHOD_GET === $method && sizeof($parameters)) { - $path .= '?' . http_build_query($parameters, '', '&'); + if (self::METHOD_GET === $method && count($parameters)) { + $url .= '?' . http_build_query($parameters, '', '&'); } - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $path); - curl_setopt($ch, CURLOPT_TIMEOUT, (int) $timeout); - curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, (int) $timeout); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); - curl_setopt($ch, CURLOPT_FAILONERROR, false); - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify); - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verify); + $curlHandler = curl_init(); + curl_setopt($curlHandler, CURLOPT_URL, $url); + curl_setopt($curlHandler, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($curlHandler, CURLOPT_FOLLOWLOCATION, 1); + curl_setopt($curlHandler, CURLOPT_FAILONERROR, false); + curl_setopt($curlHandler, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($curlHandler, CURLOPT_SSL_VERIFYHOST, false); + curl_setopt($curlHandler, CURLOPT_TIMEOUT, 30); + curl_setopt($curlHandler, CURLOPT_CONNECTTIMEOUT, 30); if (self::METHOD_POST === $method) { - curl_setopt($ch, CURLOPT_POST, true); - curl_setopt($ch, CURLOPT_POSTFIELDS, $parameters); + curl_setopt($curlHandler, CURLOPT_POST, true); + curl_setopt($curlHandler, CURLOPT_POSTFIELDS, $parameters); } - $responseBody = curl_exec($ch); - $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); - $errno = curl_errno($ch); - $error = curl_error($ch); + $responseBody = curl_exec($curlHandler); + $statusCode = curl_getinfo($curlHandler, CURLINFO_HTTP_CODE); + $errno = curl_errno($curlHandler); + $error = curl_error($curlHandler); - curl_close($ch); + curl_close($curlHandler); + + if ($errno && in_array($errno, $this->curlErrors, false) && $this->retry < 3) { + $errno = null; + $error = null; + ++$this->retry; + $this->makeRequest($path, $method, $parameters); + } if ($errno) { throw new CurlException($error, $errno); @@ -92,4 +132,14 @@ class Client return new ApiResponse($statusCode, $responseBody); } + + /** + * Retry connect + * + * @return int + */ + public function getRetry() + { + return $this->retry; + } } diff --git a/lib/RetailCrm/Response/ApiResponse.php b/lib/RetailCrm/Response/ApiResponse.php index 3997a72..8d97cd7 100644 --- a/lib/RetailCrm/Response/ApiResponse.php +++ b/lib/RetailCrm/Response/ApiResponse.php @@ -5,7 +5,15 @@ namespace RetailCrm\Response; use RetailCrm\Exception\InvalidJsonException; /** + * PHP version 5.3 + * * Response from retailCRM API + * + * @category RetailCrm + * @package RetailCrm + * @author RetailCrm + * @license https://opensource.org/licenses/MIT MIT License + * @link http://www.retailcrm.ru/docs/Developers/ApiVersion3 */ class ApiResponse implements \ArrayAccess { @@ -15,6 +23,14 @@ class ApiResponse implements \ArrayAccess // response assoc array protected $response; + /** + * ApiResponse constructor. + * + * @param int $statusCode HTTP status code + * @param mixed $responseBody HTTP body + * + * @throws InvalidJsonException + */ public function __construct($statusCode, $responseBody = null) { $this->statusCode = (int) $statusCode; @@ -57,6 +73,10 @@ class ApiResponse implements \ArrayAccess * Allow to access for the property throw class method * * @param string $name + * @param $arguments + * + * @throws \InvalidArgumentException + * * @return mixed */ public function __call($name, $arguments) @@ -75,6 +95,9 @@ class ApiResponse implements \ArrayAccess * Allow to access for the property throw object property * * @param string $name + * + * @throws \InvalidArgumentException + * * @return mixed */ public function __get($name) @@ -89,6 +112,8 @@ class ApiResponse implements \ArrayAccess /** * @param mixed $offset * @param mixed $value + * + * @throws \BadMethodCallException */ public function offsetSet($offset, $value) { @@ -97,6 +122,8 @@ class ApiResponse implements \ArrayAccess /** * @param mixed $offset + * + * @throws \BadMethodCallException */ public function offsetUnset($offset) { @@ -105,6 +132,7 @@ class ApiResponse implements \ArrayAccess /** * @param mixed $offset + * * @return bool */ public function offsetExists($offset) @@ -114,6 +142,9 @@ class ApiResponse implements \ArrayAccess /** * @param mixed $offset + * + * @throws \InvalidArgumentException + * * @return mixed */ public function offsetGet($offset) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 651ae70..6097b7b 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,11 +1,21 @@ - + + + + diff --git a/phpunit.xsd b/phpunit.xsd new file mode 100644 index 0000000..0cfae85 --- /dev/null +++ b/phpunit.xsd @@ -0,0 +1,251 @@ + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 3.7 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/RetailCrm/Test/TestCase.php b/tests/RetailCrm/Test/TestCase.php index 5eafabb..57d3067 100644 --- a/tests/RetailCrm/Test/TestCase.php +++ b/tests/RetailCrm/Test/TestCase.php @@ -27,15 +27,20 @@ class TestCase extends \PHPUnit_Framework_TestCase /** * Return Client object * - * @param string $url (default: null) - * @param string $apiKey (default: null) + * @param string $url (default: null) + * @param array $defaultParameters (default: array()) + * * @return Client */ public static function getClient($url = null, $defaultParameters = array()) { return new Client( $url ?: $_SERVER['CRM_URL'] . '/api/' . ApiClient::VERSION, - array('apiKey' => isset($defaultParameters['apiKey']) ? $defaultParameters['apiKey'] : $_SERVER['CRM_API_KEY']) + array( + 'apiKey' => array_key_exists('apiKey', $defaultParameters) + ? $defaultParameters['apiKey'] + : $_SERVER['CRM_API_KEY'] + ) ); } } diff --git a/tests/RetailCrm/Tests/ApiClientOrdersTest.php b/tests/RetailCrm/Tests/ApiClientOrdersTest.php index 1c1fc32..8d1254d 100644 --- a/tests/RetailCrm/Tests/ApiClientOrdersTest.php +++ b/tests/RetailCrm/Tests/ApiClientOrdersTest.php @@ -199,27 +199,6 @@ class ApiClientOrdersTest extends TestCase 'API returns generatedAt in orders history' ); } - - /** - * @group integration - */ - public function testOrdersPacksHistory() - { - $client = static::getApiClient(); - - $response = $client->ordersPacksHistory(); - $this->assertInstanceOf('RetailCrm\Response\ApiResponse', $response); - $this->assertEquals(200, $response->getStatusCode()); - $this->assertTrue($response->success); - $this->assertTrue( - isset($response['history']), - 'API returns orders assembly history' - ); - $this->assertTrue( - isset($response['generatedAt']), - 'API returns generatedAt in orders assembly history' - ); - } /** * @group integration diff --git a/tests/RetailCrm/Tests/ApiClientPacksTest.php b/tests/RetailCrm/Tests/ApiClientPacksTest.php new file mode 100644 index 0000000..cc51764 --- /dev/null +++ b/tests/RetailCrm/Tests/ApiClientPacksTest.php @@ -0,0 +1,91 @@ +ordersPacksHistory(); + $this->assertInstanceOf('RetailCrm\Response\ApiResponse', $response); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertTrue($response->success); + $this->assertTrue( + isset($response['history']), + 'API returns orders assembly history' + ); + $this->assertTrue( + isset($response['generatedAt']), + 'API returns generatedAt in orders assembly history' + ); + } + + /** + * @group integration + */ + public function testOrdersPacksCreate() + { + $client = static::getApiClient(); + $pack = array( + 'itemId' => $_SERVER['CRM_PACK_ITEM'], + 'quantity' => $_SERVER['CRM_PACK_QUANTITY'], + 'store' => $_SERVER['CRM_STORE'] + ); + + $response = $client->ordersPacksCreate($pack); + $this->assertInstanceOf('RetailCrm\Response\ApiResponse', $response); + $this->assertEquals(201, $response->getStatusCode()); + $this->assertTrue($response->success); + } + + /** + * @group integration + */ + public function testOrdersPacksCreateFailed() + { + $client = static::getApiClient(); + $pack = array( + 'itemId' => 12, + 'store' => $_SERVER['CRM_STORE'], + 'quantity' => 2 + ); + + $response = $client->ordersPacksCreate($pack); + $this->assertInstanceOf('RetailCrm\Response\ApiResponse', $response); + $this->assertEquals(400, $response->getStatusCode()); + $this->assertFalse($response->success); + } + + /** + * @group integration + */ + public function testOrdersPacksGet() + { + $client = static::getApiClient(); + + $response = $client->ordersPacksGet(1); + $this->assertInstanceOf('RetailCrm\Response\ApiResponse', $response); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertTrue($response->success); + } + + /** + * @group integration + */ + public function testOrdersPacksDelete() + { + $client = static::getApiClient(); + + $response = $client->ordersPacksDelete(1); + $this->assertInstanceOf('RetailCrm\Response\ApiResponse', $response); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertTrue($response->success); + } +} diff --git a/tests/RetailCrm/Tests/ApiClientStoreTest.php b/tests/RetailCrm/Tests/ApiClientStoreTest.php index de354b0..32b323c 100644 --- a/tests/RetailCrm/Tests/ApiClientStoreTest.php +++ b/tests/RetailCrm/Tests/ApiClientStoreTest.php @@ -4,6 +4,10 @@ namespace RetailCrm\Tests; use RetailCrm\Test\TestCase; +/** + * Class ApiClientStoreTest + * @package RetailCrm\Tests + */ class ApiClientStoreTest extends TestCase { /** @@ -30,8 +34,7 @@ class ApiClientStoreTest extends TestCase public function testStoreInventoriesUploadExceptionEmpty() { $client = static::getApiClient(); - - $response = $client->storeInventoriesUpload(array()); + $client->storeInventoriesUpload(array()); } /** @@ -47,20 +50,27 @@ class ApiClientStoreTest extends TestCase $response = $client->storeInventoriesUpload(array( array( 'externalId' => $externalIdA, - 'available' => 10, - 'purchasePrice' => 1700 + 'stores' => array( + array( + 'code' => $_SERVER['CRM_STORE'], + 'available' => 10, + 'purchasePrice' => 1700 + ) + ) ), array( 'externalId' => $externalIdB, - 'available' => 20, - 'purchasePrice' => 1500 + 'stores' => array( + array( + 'code' => $_SERVER['CRM_STORE'], + 'available' => 20, + 'purchasePrice' => 1500 + ) + ) ), )); $this->assertInstanceOf('RetailCrm\Response\ApiResponse', $response); - $this->assertTrue( - $response->isSuccessful(), - 'Got offer' - ); + $this->assertTrue($response->isSuccessful()); } /** diff --git a/tests/RetailCrm/Tests/Http/ClientTest.php b/tests/RetailCrm/Tests/Http/ClientTest.php index 84eecf2..bbecdf8 100644 --- a/tests/RetailCrm/Tests/Http/ClientTest.php +++ b/tests/RetailCrm/Tests/Http/ClientTest.php @@ -58,14 +58,4 @@ class ClientTest extends TestCase $this->assertInstanceOf('RetailCrm\Response\ApiResponse', $response); $this->assertEquals(200, $response->getStatusCode()); } - - /** - * @group integration - * @expectedException \RetailCrm\Exception\CurlException - */ - public function testMakeRequestTimeout() - { - $client = static::getClient(); - $client->makeRequest('/orders', Client::METHOD_GET, array(), 1, false, true); - } } diff --git a/tests/RetailCrm/Tests/Response/ApiResponseTest.php b/tests/RetailCrm/Tests/Response/ApiResponseTest.php index fa70176..74e0fab 100644 --- a/tests/RetailCrm/Tests/Response/ApiResponseTest.php +++ b/tests/RetailCrm/Tests/Response/ApiResponseTest.php @@ -29,7 +29,7 @@ class ApiResponseTest extends TestCase /** * @group unit - * @expectedException RetailCrm\Exception\InvalidJsonException + * @expectedException \RetailCrm\Exception\InvalidJsonException */ public function testJsonInvalid() {