├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── assets ├── yclients-logo-social.png └── yclients-logo.png ├── composer.json └── src └── Yclients ├── YclientsApi.php ├── YclientsException.php ├── YclientsRequest.php └── cacert.pem /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | examples/ 3 | logs/ 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 slowprog 4 | Copyright (c) 2019-2024 andrey-tech 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # YCLIENTS API PHP Wrapper 2 | 3 | ![YCLIENTS logo](./assets/yclients-logo.png) 4 | 5 | Обертка на PHP7+ для работы с [REST API YCLIENTS v2.0](https://yclients.docs.apiary.io/) 6 | c троттлингом запросов к API и логированием в файл. 7 | 8 | Данная библиотека является форком [Yclients API wrapper](https://github.com/slowprog/yclients-api) со следующими изменениями: 9 | 10 | - добавлен регулируемый троттлинг запросов к API; 11 | - добавлена отключаемая проверка SSL/TLS-сертификата сервера YCLIENTS; 12 | - добавлена проверка наличия сообщений об ошибках в ответе API; 13 | - добавлено логирование запросов и ответов сервера в файл или STDOUT; 14 | - изменен и дополнен тест сообщений об ошибках; 15 | - добавлены методы getSchedule(), getGroups(); 16 | - изменен метод postHooks() в связи с изменениями в API; 17 | - добавлен метод getAll() для выгрузки всех сущностей одного типа с использованием генератора при обработке больших объемов данных. 18 | 19 | ## Содержание 20 | 21 | 22 | 23 | - [Требования](#%D0%A2%D1%80%D0%B5%D0%B1%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F) 24 | - [Установка](#%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0) 25 | - [Класс `YclientsApi`](#%D0%9A%D0%BB%D0%B0%D1%81%D1%81-yclientsapi) 26 | - [Список методов класса](#%D0%A1%D0%BF%D0%B8%D1%81%D0%BE%D0%BA-%D0%BC%D0%B5%D1%82%D0%BE%D0%B4%D0%BE%D0%B2-%D0%BA%D0%BB%D0%B0%D1%81%D1%81%D0%B0) 27 | - [Авторизация](#%D0%90%D0%B2%D1%82%D0%BE%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F) 28 | - [Онлайн-запись](#%D0%9E%D0%BD%D0%BB%D0%B0%D0%B9%D0%BD-%D0%B7%D0%B0%D0%BF%D0%B8%D1%81%D1%8C) 29 | - [Записи пользователя](#%D0%97%D0%B0%D0%BF%D0%B8%D1%81%D0%B8-%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8F) 30 | - [Сети салонов](#%D0%A1%D0%B5%D1%82%D0%B8-%D1%81%D0%B0%D0%BB%D0%BE%D0%BD%D0%BE%D0%B2) 31 | - [Компании](#%D0%9A%D0%BE%D0%BC%D0%BF%D0%B0%D0%BD%D0%B8%D0%B8) 32 | - [Категория услуг](#%D0%9A%D0%B0%D1%82%D0%B5%D0%B3%D0%BE%D1%80%D0%B8%D1%8F-%D1%83%D1%81%D0%BB%D1%83%D0%B3) 33 | - [Услуги](#%D0%A3%D1%81%D0%BB%D1%83%D0%B3%D0%B8) 34 | - [Сотрудники](#%D0%A1%D0%BE%D1%82%D1%80%D1%83%D0%B4%D0%BD%D0%B8%D0%BA%D0%B8) 35 | - [Клиенты](#%D0%9A%D0%BB%D0%B8%D0%B5%D0%BD%D1%82%D1%8B) 36 | - [Записи](#%D0%97%D0%B0%D0%BF%D0%B8%D1%81%D0%B8) 37 | - [Расписание работы сотрудников](#%D0%A0%D0%B0%D1%81%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5-%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B-%D1%81%D0%BE%D1%82%D1%80%D1%83%D0%B4%D0%BD%D0%B8%D0%BA%D0%BE%D0%B2) 38 | - [Даты для журнала](#%D0%94%D0%B0%D1%82%D1%8B-%D0%B4%D0%BB%D1%8F-%D0%B6%D1%83%D1%80%D0%BD%D0%B0%D0%BB%D0%B0) 39 | - [Комментарии](#%D0%9A%D0%BE%D0%BC%D0%BC%D0%B5%D0%BD%D1%82%D0%B0%D1%80%D0%B8%D0%B8) 40 | - [Пользователи компании](#%D0%9F%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D0%B8-%D0%BA%D0%BE%D0%BC%D0%BF%D0%B0%D0%BD%D0%B8%D0%B8) 41 | - [Кассы](#%D0%9A%D0%B0%D1%81%D1%81%D1%8B) 42 | - [SMS рассылка](#sms-%D1%80%D0%B0%D1%81%D1%81%D1%8B%D0%BB%D0%BA%D0%B0) 43 | - [Склады](#%D0%A1%D0%BA%D0%BB%D0%B0%D0%B4%D1%8B) 44 | - [Уведомления о событиях webhooks](#%D0%A3%D0%B2%D0%B5%D0%B4%D0%BE%D0%BC%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F-%D0%BE-%D1%81%D0%BE%D0%B1%D1%8B%D1%82%D0%B8%D1%8F%D1%85-webhooks) 45 | - [Вспомогательные методы](#%D0%92%D1%81%D0%BF%D0%BE%D0%BC%D0%BE%D0%B3%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B5-%D0%BC%D0%B5%D1%82%D0%BE%D0%B4%D1%8B) 46 | - [Дополнительные параметры](#%D0%94%D0%BE%D0%BF%D0%BE%D0%BB%D0%BD%D0%B8%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B5-%D0%BF%D0%B0%D1%80%D0%B0%D0%BC%D0%B5%D1%82%D1%80%D1%8B) 47 | - [Примеры](#%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B) 48 | - [Авторы](#%D0%90%D0%B2%D1%82%D0%BE%D1%80%D1%8B) 49 | - [Лицензия](#%D0%9B%D0%B8%D1%86%D0%B5%D0%BD%D0%B7%D0%B8%D1%8F) 50 | 51 | 52 | 53 | 54 | ## Требования 55 | 56 | - PHP >= 7.0. 57 | - Произвольный автозагрузчик классов, реализующий стандарт [PSR-4](https://www.php-fig.org/psr/psr-4/). 58 | 59 | 60 | 61 | ## Установка 62 | 63 | Установка через composer: 64 | ``` 65 | $ composer require andrey-tech/yclients-api-php 66 | ``` 67 | 68 | или добавить 69 | 70 | ``` 71 | "andrey-tech/yclients-api-php": "^1.7" 72 | ``` 73 | 74 | в секцию require файла composer.json. 75 | 76 | 77 | 78 | ## Класс `YclientsApi` 79 | 80 | Для работы с REST API YCLIENTS используется методы класса `\Yclients\YclientsApi`. 81 | При возникновении ошибок выбрасывается исключение с объектом класса `\Yclients\YclientsException`. 82 | 83 | 84 | ### Список методов класса 85 | 86 | - `__construct(string $tokenPartner = null)` Конструктор класса. 87 | 88 | 89 | #### Авторизация 90 | 91 | - `setTokenPartner(string $tokenPartner) :void` Устанавливает токен партнера. 92 | - `getTokenPartner() :string` Возвращает токен партнера. 93 | - `getAuth(string $login, string $password) :array` Выполняет авторизацию и возвращает токен пользователя. 94 | 95 | 96 | #### Онлайн-запись 97 | 98 | - `getBookform($id) :array` Возвращает настройки формы бронирования. 99 | - `getI18n($locale = 'ru-RU') :array` Возвращает параметры интернационализации. 100 | - `getBookServices($companyId, $staffId = null, \DateTime $datetime = null, array $serviceIds = null, array $eventIds = null) :array` 101 | Возвращает список услуг, доступных для бронирования. 102 | - `getBookStaff($companyId, $staffId = null, \DateTime $datetime = null, array $serviceIds = null, array $eventIds = null, $withoutSeances = false) :array` 103 | Возвращает список сотрудников, доступных для бронирования. 104 | - `getBookDates($companyId, $staffId = null, array $serviceIds = null, \DateTime $date = null, array $eventIds = null) :array` 105 | Возвращает список дат, доступных для бронирования. 106 | - `getBookTimes($companyId, $staffId, \DateTime $date, array $serviceIds = null, array $eventIds = null) : array` 107 | Возвращает список сеансов, доступных для бронирования. 108 | - `postBookCode($companyId, $phone, $fullname = null) :array` Отправляет СМС код подтверждения номера телефона. 109 | - `postBookCheck($companyId, array $appointments): array` Проверяет параметры записи. 110 | - `postBookRecord($companyId, array $person, array $appointments, $code = null, array $notify = null, $comment = null, $apiId = null) :array` 111 | Создает запись на сеанс. 112 | 113 | 114 | #### Записи пользователя 115 | 116 | - `postUserAuth($phone, $code) :array` Выполняет авторизовацию пользователя по номеру телефона и SMS-коду. 117 | - `getUserRecords($recordId, $recordHash = null, $userToken = null): array` Возвращает записи пользователя. 118 | - `deleteUserRecords($recordId, $recordHash = null, $userToken = null): array` Удаляет записи пользователя. 119 | 120 | 121 | #### Сети салонов 122 | 123 | - `getGroups($userToken): array` Возвращает список доступных сетей салонов 124 | 125 | 126 | #### Компании 127 | 128 | - `getCompanies($groupId = null, $active = null, $moderated = null, $forBooking = null, $my = null, $userToken = null) :array` 129 | Возвращает список компаний. 130 | - `postCompany(array $fields, $userToken) :array` Создает компанию. 131 | - `getCompany($id) :array` Возвращает компанию. 132 | - `putCompany($id, array $fields, $userToken) :array` Изменяет компанию. 133 | - `deleteCompany($id) :array` Удаляет компанию. 134 | - `getCompanyAnalytics($companyId, $dateFrom, $dateTo, $userToken)` Возвращает основные показатели компании. 135 | 136 | 137 | #### Категория услуг 138 | 139 | - `getServiceCategories($companyId, $categoryId = null, $staffId = null) :array` Возвращает список категорий услуг. 140 | - `postServiceCategories($companyId, $categoryId, $fields, $userToken) :array` Создает категорию услуг. 141 | - `getServiceCategory($companyId, $categoryId) :array` Возвращает категорию услуг. 142 | - `putServiceCategory($companyId, $categoryId, $fields, $userToken) :array` Изменяет категорию услуг. 143 | - `deleteServiceCategory($companyId, $categoryId, $userToken) :array` Удаляет категорию услуг. 144 | 145 | 146 | #### Услуги 147 | 148 | - `getServices($companyId, $serviceId = null, $staffId = null, $categoryId = null) :array` Возвращает список услуг или конкретную услугу. 149 | - `postServices($companyId, $serviceId, $categoryId, $title, $userToken, array $fields = null) :array` Создает новую услугу. 150 | - `putServices($companyId, $serviceId, $categoryId, $title, $userToken, array $fields = null) :array` Изменяет услугу. 151 | - `deleteServices($companyId, $serviceId, $userToken) :array` Удаляет услугу. 152 | 153 | 154 | #### Сотрудники 155 | 156 | - `getStaff($companyId, $staffId = null) :array` Возвращает список сотрудников или конкретного сотрудника. 157 | - `postStaff($companyId, $staffId, $name, $userToken, array $fields = null) :array` Добавляет нового сотрудника. 158 | - `putStaff($companyId, $staffId, array $fields, $userToken) :array` Изменяет сотрудника. 159 | - `deleteStaff($companyId, $staffId, $userToken) :array` Удаляет сотрудника. 160 | 161 | 162 | #### Клиенты 163 | 164 | - `getClients($companyId, $userToken, $fullname = null, $phone = null, $email = null, $page = null, $count = null) :array` 165 | Возвращает список клиентов. 166 | - `postClients($companyId, $name, $phone, $userToken, array $fields = []) :array` Добавляет клиента. 167 | - `getClient($companyId, $id, $userToken) :array` Возвращает клиента. 168 | - `putClient($companyId, $id, $userToken, array $fields) :array` Изменяет клиента. 169 | - `deleteClient($companyId, $id, $userToken) :array` Удаляет клиента. 170 | 171 | 172 | #### Записи 173 | 174 | - `getRecords($companyId, $userToken, $page = null, $count = null, $staffId = null, $clientId = null, \DateTime $startDate = null, \DateTime $endDate = null, \DateTime $cStartDate = null, \DateTime $cEndDate = null, \DateTime $changedAfter = null, \DateTime $changedBefore = null) :array` 175 | Возвращает список записей. 176 | - `postRecords($companyId, $userToken, $staffId, $services, $client, \DateTime $datetime, $seanceLength, $saveIfBusy, $sendSms, $comment = null, $smsRemainHours = null, $emailRemainHours = null, $apiId = null, $attendance = null) :array` 177 | Создает новую запись. 178 | - `getRecord($companyId, $recordId, $userToken) :array` Возвращает запись. 179 | - `putRecord($companyId, $recordId, $userToken, array $fields) :array` Изменяет запись. 180 | - `deleteRecord($companyId, $recordId, $userToken) :array` Удаляет запись. 181 | 182 | 183 | #### Расписание работы сотрудников 184 | 185 | - `getSchedule($companyId, $staffId, $startDate, $endDate, $userToken) :array` Возвращает расписание работы сотрудника. 186 | - `putSchedule($companyId, $staffId, $userToken, $fields) :array` Изменяет расписание работы сотрудника. 187 | 188 | 189 | #### Даты для журнала 190 | 191 | - `getTimetableDates($companyId, \DateTime $date, $staffId, $userToken) :array` Возвращает список дат для журнала. 192 | - `getTimetableSeances($companyId, \DateTime $date, $staffId, $userToken) :array` Возвращает список сеансов для журнала. 193 | 194 | 195 | #### Комментарии 196 | 197 | - `getComments($companyId, $userToken, \DateTime $startDate = null, \DateTime $endDate = null, $staffId = null, $rating = null) :array` 198 | Возвращает комментарии. 199 | 200 | 201 | #### Пользователи компании 202 | 203 | - `getCompanyUsers($companyId, $userToken) :array` Возвращает пользователей компании. 204 | 205 | 206 | #### Кассы 207 | 208 | - `getAccounts($companyId, $userToken) :array` Возвращает кассы компании. 209 | 210 | 211 | #### SMS рассылка 212 | 213 | - `sendSMS($companyId, $userToken, $clientIds, $text) :array` Отправляет SMS. 214 | 215 | 216 | #### Склады 217 | 218 | - `getStorages($companyId, $userToken) :array` Возвращает склады компании. 219 | 220 | 221 | #### Уведомления о событиях webhooks 222 | 223 | - `getHooks($companyId, $userToken) :array` Возвращает настройки уведомлений о событиях. 224 | - `postHooks($companyId, $fields, $userToken) :array` Изменяет настройки уведомлений о событиях. 225 | 226 | 227 | #### Вспомогательные методы 228 | 229 | - `getAll($callback) :\Generator` Загружает все сущности одного типа. 230 | + `$callback` - анонимная функция `function(int $page, int $count) { ... }`, реализующая постраничную загрузку сущностей 231 | с помощью методов `getClients()` или `getRecords()`: 232 | * `$page` - номер загружаемой страницы; 233 | * `$count` - максимальное количество сущностей, загружаемых на странице. 234 | 235 | 236 | ### Дополнительные параметры 237 | 238 | Дополнительные параметры работы устанавливаются через публичные свойства объекта класса `YclientsApi`. 239 | 240 | | Свойство | По умолчанию | Описание | 241 | |-------------------------|----------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 242 | | `$debug` | false | Включает отладочный режим с сохранением запросов и ответов в лог файл или выводом в STDOUT | 243 | | `$debugLogFile` | logs/debug.log | Устанавливает лог файл отладочного режима (null - вывод в STDOUT) | 244 | | `$throttle` | 5 | Устанавливает максимальное число запросов к API YCLIENTS в секунду ([не более 5 запросов в секунду](https://yclients.docs.apiary.io/)), значение 0 отключает троттлинг запросов к API | 245 | | `$verifySSLCerfificate` | true | Включает проверку SSL/TLS-сертификата сервера YCLIENTS | 246 | | `$SSLCertificateFile` | 'cacert.pem' | Устанавливает файл SSL/TLS-сертификатов X.509 корневых удостоверяющих центров (CA) в формате РЕМ (null - файл, указанный в `curl.cainfo` php.ini) | 247 | | `$curlConnectTimeout` | 30 | Устанавливает таймаут соединения с сервером YCLIENTS, секунды | 248 | | `$curlTimeout` | 30 | Устанавливает таймаут обмена данными с сервером YCLIENTS, секунды | 249 | | `$limitCount` | 300 | Максимальное количество сушностей, загружаемых за один запрос к API в методе `getAll()` | 250 | 251 | 252 | ### Примеры 253 | 254 | ```php 255 | use Yclients\YclientsApi; 256 | 257 | try { 258 | 259 | $login = 'user@example.com'; 260 | $password = '37*%4Hd.Uda)532'; 261 | $tokenPartner = 'erd8jrpo4mk7lsk8krs'; 262 | 263 | $yc = new YclientsApi($tokenPartner); 264 | 265 | // Включаем отладочный режим с логированием в файл 266 | $yc->debug = true; 267 | 268 | // Устанавливаем лог файл отладочного режима 269 | $ys->debugLogFile = 'logs/debug_yclients_api.log'; 270 | 271 | // Устанавливает максимальное число запросов к API YCLIENTS в секунду (значение 0 отключает троттлинг запросов к API) 272 | $yc->throttle = 1; 273 | 274 | // Выполняем авторизацию и получаем токен пользователя 275 | $response = $yc->getAuth($login, $password); 276 | $userToken = $response['user_token']; 277 | 278 | /* 279 | * Получаем список активных, прошедших модерацию компаний YCLINETS, 280 | * на управление которыми пользователь имеет права 281 | */ 282 | $companies = $yc->getCompanies( 283 | $groupId = null, 284 | $active = true, 285 | $moderated = true, 286 | $forBooking = null, 287 | $my = 1, 288 | $userToken 289 | ); 290 | 291 | // Получаем ID первой компании 292 | $companyId = $companies[0]['id']; 293 | 294 | // Получаем всех пользователей первой компании 295 | $users = $yc->getCompanyUsers($companyId, $userToken); 296 | print_r($users); 297 | 298 | // Получаем всех сотрудников компании 299 | $staff = $yc->getStaff($companyId); 300 | print_r($staff); 301 | 302 | // Получаем ID первого сотрудника 303 | $workerId = $staff[0]['id']; 304 | 305 | // Загружаем расписание работы первого сотрудника на 1 месяц 306 | $schedule = $yc->getSchedule( 307 | $companyId, 308 | $workerId, 309 | $startDate = '2020-01-01', 310 | $endDate = '2020-01-31' 311 | $userToken 312 | ); 313 | print_r($schedule); 314 | 315 | /** 316 | * Выгружаем всех клиентов заданной компании с использованием генератора 317 | * при обработке больших объемов данных 318 | */ 319 | $generator = $yc->getAll( 320 | function (int $page, int $count) use ($yc, $companyId, $userToken) { 321 | return $yc->getClients( 322 | $companyId, 323 | $userToken, 324 | $fullname = null, 325 | $phone = null, 326 | $email = null, 327 | $page, 328 | $count 329 | ); 330 | } 331 | ); 332 | foreach ($generator as $response) { 333 | $clients = $response['data']; 334 | foreach ($clients as $client) { 335 | print_r($client); 336 | } 337 | } 338 | 339 | /** 340 | * Выгружаем все записи сотрудника заданной компании с использованием генератора 341 | * при обработке больших объемов данных 342 | */ 343 | $generator = $yc->getAll( 344 | function (int $page, int $count) use ($yc, $companyId, $userToken, $workerId) { 345 | return $yc->getRecords( 346 | $companyId, 347 | $userToken, 348 | $page, 349 | $count, 350 | $workerId 351 | ); 352 | } 353 | ); 354 | foreach ($generator as $response) { 355 | $records = $response['data']; 356 | foreach ($records as $record) { 357 | print_r($record); 358 | } 359 | } 360 | 361 | } catch (\Yclients\YclientsException $e) { 362 | printf('Ошибка (%d): %s' . PHP_EOL, $e->getCode(), $e->getMessage()); 363 | } 364 | ``` 365 | 366 | 367 | ## Авторы 368 | 369 | © 2018 slowprog 370 | © 2019-2024 andrey-tech 371 | 372 | 373 | ## Лицензия 374 | 375 | Данная библиотека распространяется на условиях лицензии [MIT](./LICENSE). 376 | -------------------------------------------------------------------------------- /assets/yclients-logo-social.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrey-tech/yclients-api-php/2f29b177bbaa118ab4db1288b913ba4545975978/assets/yclients-logo-social.png -------------------------------------------------------------------------------- /assets/yclients-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrey-tech/yclients-api-php/2f29b177bbaa118ab4db1288b913ba4545975978/assets/yclients-logo.png -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "andrey-tech/yclients-api-php", 3 | "description": "Обертка для работы с API YCLIENTS v2.0 c троттлингом запросов и логированием в файл", 4 | "keywords": [ "yclients", "api", "api-wrapper", "throttling", "logging" ], 5 | "homepage": "https://github.com/andrey-tech/yclients-api-php", 6 | "minimum-stability": "stable", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "andrey-tech", 11 | "homepage": "https://github.com/andrey-tech/", 12 | "role": "Developer" 13 | }, 14 | { 15 | "name": "Andrey Tyshev", 16 | "role": "Developer" 17 | } 18 | ], 19 | "require": { 20 | "php": ">=7.0", 21 | "ext-curl": "*", 22 | "ext-json": "*" 23 | }, 24 | "autoload": { 25 | "psr-4": { 26 | "Yclients\\": "src/Yclients" 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Yclients/YclientsApi.php: -------------------------------------------------------------------------------- 1 | setTokenPartner($tokenPartner); 79 | } 80 | 81 | /** 82 | * Установку токена можно сделать отдельно т.к. есть запросы не 83 | * требующие авторизации партнёра 84 | * 85 | * @param string $tokenPartner 86 | * @return self 87 | * @access public 88 | */ 89 | public function setTokenPartner($tokenPartner) 90 | { 91 | $this->tokenPartner = $tokenPartner; 92 | 93 | return $this; 94 | } 95 | 96 | public function getTokenPartner() 97 | { 98 | return $this->tokenPartner; 99 | } 100 | 101 | /** 102 | * Получаем токен пользователя по логину-паролю 103 | * 104 | * @param string $login 105 | * @param string $password 106 | * @return array 107 | * @access public 108 | * @see http://docs.yclients.apiary.io/#reference/0/0/0 109 | * @throws YclientsException 110 | */ 111 | public function getAuth($login, $password) 112 | { 113 | return $this->request('auth', [ 114 | 'login' => $login, 115 | 'password' => $password, 116 | ], self::METHOD_POST); 117 | } 118 | 119 | /** 120 | * Получаем настройки формы бронирования 121 | * 122 | * @param integer $id 123 | * @return array 124 | * @access public 125 | * @see http://docs.yclients.apiary.io/#reference/-/0/0 126 | * @throws YclientsException 127 | */ 128 | public function getBookform($id) 129 | { 130 | return $this->request('bookform/' . $id); 131 | } 132 | 133 | /** 134 | * Получаем параметры интернационализации 135 | * 136 | * @param string $locale - ru-RU, lv-LV, en-US, ee-EE, lt-LT, de-DE, uk-UK 137 | * @return array 138 | * @access public 139 | * @see http://docs.yclients.apiary.io/#reference/-/1/0 140 | * @throws YclientsException 141 | */ 142 | public function getI18n($locale = 'ru-RU') 143 | { 144 | return $this->request('i18n/' . $locale); 145 | } 146 | 147 | /** 148 | * Получить список услуг доступных для бронирования 149 | * 150 | * @param integer $companyId 151 | * @param integer $staffId - ID сотрудника. Фильтр по идентификатору сотрудника 152 | * @param \DateTime $datetime - дата (в формате iso8601). Фильтр по дате 153 | * бронирования услуги (например '2005-09-09T18:30') 154 | * @param array $serviceIds - ID услуг. Фильтр по списку идентификаторов уже 155 | * выбранных (в рамках одной записи) услуг. Имеет 156 | * смысл если зада фильтр по мастеру и дате. 157 | * @param array $eventIds - ID акций. Фильтр по списку идентификаторов уже выбранных 158 | * (в рамках одной записи) акций. Имеет смысл если зада 159 | * фильтр по мастеру и дате. 160 | * @return array 161 | * @access public 162 | * @see http://docs.yclients.apiary.io/#reference/-/2/0 163 | * @throws YclientsException 164 | */ 165 | public function getBookServices( 166 | $companyId, 167 | $staffId = null, 168 | \DateTime $datetime = null, 169 | array $serviceIds = null, 170 | array $eventIds = null 171 | ) { 172 | $parameters = []; 173 | 174 | if ($staffId !== null) { 175 | $parameters['staff_id'] = $staffId; 176 | } 177 | 178 | if ($datetime !== null) { 179 | $parameters['datetime'] = $datetime->format(\DateTime::ISO8601); 180 | } 181 | 182 | if ($serviceIds !== null) { 183 | $parameters['service_ids'] = $serviceIds; 184 | } 185 | 186 | if ($eventIds !== null) { 187 | $parameters['event_ids'] = $eventIds; 188 | } 189 | 190 | return $this->request('book_services/' . $companyId, $parameters); 191 | } 192 | 193 | /** 194 | * Получить список сотрудников доступных для бронирования 195 | * 196 | * @param integer $companyId 197 | * @param integer $staffId - ID сотрудника. Фильтр по идентификатору сотрудника 198 | * @param \DateTime $datetime - дата (в формате iso8601). Фильтр по дате 199 | * бронирования услуги (например '2005-09-09T18:30') 200 | * @param array $serviceIds - ID услуг. Фильтр по списку идентификаторов уже 201 | * выбранных (в рамках одной записи) услуг. Имеет 202 | * смысл если зада фильтр по мастеру и дате. 203 | * @param array $eventIds - ID акций. Фильтр по списку идентификаторов уже выбранных 204 | * (в рамках одной записи) акций. Имеет смысл если зада 205 | * фильтр по мастеру и дате. 206 | * @param bool $withoutSeances - Отключает выдачу ближайших свободных сеансов, 207 | * ускоряет получение данных. 208 | * @return array 209 | * @access public 210 | * @see http://docs.yclients.apiary.io/#reference/-/3/0 211 | * @throws YclientsException 212 | */ 213 | public function getBookStaff( 214 | $companyId, 215 | $staffId = null, 216 | \DateTime $datetime = null, 217 | array $serviceIds = null, 218 | array $eventIds = null, 219 | $withoutSeances = false 220 | ) { 221 | $parameters = []; 222 | 223 | if ($staffId !== null) { 224 | $parameters['staff_id'] = $staffId; 225 | } 226 | 227 | if ($datetime !== null) { 228 | $parameters['datetime'] = $datetime->format(\DateTime::ISO8601); 229 | } 230 | 231 | if ($serviceIds !== null) { 232 | $parameters['service_ids'] = $serviceIds; 233 | } 234 | 235 | if ($eventIds !== null) { 236 | $parameters['event_ids'] = $eventIds; 237 | } 238 | 239 | if ($withoutSeances) { 240 | $parameters['without_seances'] = true; 241 | } 242 | 243 | return $this->request('book_staff/' . $companyId, $parameters); 244 | } 245 | 246 | /** 247 | * Получить список дат доступных для бронирования 248 | * 249 | * @param integer $companyId 250 | * @param integer $staffId - ID сотрудника. Фильтр по идентификатору сотрудника 251 | * @param array $serviceIds - ID услуг. Фильтр по списку идентификаторов уже 252 | * выбранных (в рамках одной записи) услуг. Имеет 253 | * смысл если зада фильтр по мастеру и дате. 254 | * @param \DateTime $date - Фильтр по месяцу бронирования (например '2015-09-01') 255 | * @param array $eventIds - ID акций. Фильтр по списку идентификаторов уже выбранных 256 | * (в рамках одной записи) акций. Имеет смысл если зада 257 | * фильтр по мастеру и дате. 258 | * @return array 259 | * @access public 260 | * @see http://docs.yclients.apiary.io/#reference/-/4/0 261 | * @throws YclientsException 262 | */ 263 | public function getBookDates( 264 | $companyId, 265 | $staffId = null, 266 | array $serviceIds = null, 267 | \DateTime $date = null, 268 | array $eventIds = null 269 | ) { 270 | $parameters = []; 271 | 272 | if ($staffId !== null) { 273 | $parameters['staff_id'] = $staffId; 274 | } 275 | 276 | if ($date !== null) { 277 | $parameters['date'] = $date->format('Y-m-d'); 278 | } 279 | 280 | if ($serviceIds !== null) { 281 | $parameters['service_ids'] = $serviceIds; 282 | } 283 | 284 | if ($eventIds !== null) { 285 | $parameters['event_ids'] = $eventIds; 286 | } 287 | 288 | return $this->request('book_dates/' . $companyId, $parameters); 289 | } 290 | 291 | /** 292 | * Получить список сеансов доступных для бронирования 293 | * 294 | * @param integer $companyId 295 | * @param integer $staffId - ID сотрудника. Фильтр по идентификатору сотрудника 296 | * @param \DateTime $date - Фильтр по месяцу бронирования (например '2015-09-01') 297 | * @param array $serviceIds - ID услуг. Фильтр по списку идентификаторов уже 298 | * выбранных (в рамках одной записи) услуг. Имеет 299 | * смысл если зада фильтр по мастеру и дате. 300 | * @param array $eventIds - ID акций. Фильтр по списку идентификаторов уже выбранных 301 | * (в рамках одной записи) акций. Имеет смысл если зада 302 | * фильтр по мастеру и дате. 303 | * @return array 304 | * @access public 305 | * @see http://docs.yclients.apiary.io/#reference/-/5/0 306 | * @throws YclientsException 307 | */ 308 | public function getBookTimes( 309 | $companyId, 310 | $staffId, 311 | \DateTime $date, 312 | array $serviceIds = null, 313 | array $eventIds = null 314 | ) { 315 | $parameters = []; 316 | 317 | if ($serviceIds !== null) { 318 | $parameters['service_ids'] = $serviceIds; 319 | } 320 | 321 | if ($eventIds !== null) { 322 | $parameters['event_ids'] = $eventIds; 323 | } 324 | 325 | return $this->request('book_times/' . $companyId . '/' . $staffId . '/' . $date->format('Y-m-d'), $parameters); 326 | } 327 | 328 | /** 329 | * Отправить СМС код подтверждения номера телефона 330 | * 331 | * @param integer $companyId 332 | * @param string $phone - Телефон, на который будет отправлен код, вида 79991234567 333 | * @param string $fullname - Имя клиента 334 | * @return array 335 | * @access public 336 | * @see http://docs.yclients.apiary.io/#reference/-/6/0 337 | * @throws YclientsException 338 | */ 339 | public function postBookCode($companyId, $phone, $fullname = null) 340 | { 341 | $parameters = [ 342 | 'phone' => $phone 343 | ]; 344 | 345 | if ($fullname !== null) { 346 | $parameters['fullname'] = $fullname; 347 | } 348 | 349 | return $this->request('book_code/' . $companyId, $parameters, self::METHOD_POST); 350 | } 351 | 352 | /** 353 | * Проверить параметры записи 354 | * 355 | * @param integer $companyId 356 | * @param array $appointments - Массив записей со следующими полями: 357 | * integer id - Идентификатор записи 358 | * array services - Массив идентификторов услуг 359 | * array events - Массив идентификторов акций 360 | * integer staff_id - Идентификатор специалиста 361 | * string datetime - Дата и время сеанса в формате ISO8601 (2015-09-29T13:00:00+04:00) 362 | * @return array 363 | * @access public 364 | * @see http://docs.yclients.apiary.io/#reference/-/7/0 365 | * @throws YclientsException 366 | */ 367 | public function postBookCheck($companyId, array $appointments) 368 | { 369 | // проверим наличие обязательных параметров 370 | foreach ($appointments as $appointment) { 371 | if (!isset($appointment['id'], $appointment['staff_id'], $appointment['datetime'])) { 372 | throw new YclientsException('Запись должна содержать все обязательные поля: id, staff_id, datetime.'); 373 | } 374 | } 375 | 376 | return $this->request('book_check/' . $companyId, $appointments, self::METHOD_POST); 377 | } 378 | 379 | /** 380 | * Создать запись на сеанс 381 | * 382 | * @param integer $companyId 383 | * @param array $person - Массив обязательных данных клиента со следующими полями: 384 | * string phone - Телефон клиента вида 79161502239 385 | * string fullname 386 | * string email 387 | * @param array $appointments - Массив записей со следующими полями: 388 | * integer id - Идентификатор записи для обратной связи 389 | * array services - Массив идентификторов услуг 390 | * array events - Массив идентификторов акций 391 | * integer staff_id - Идентификатор специалиста 392 | * string datetime - Дата и время сеанса в формате ISO8601 (2015-09-29T13:00:00+04:00) 393 | * @param string $code - Код подтверждения номера телефона 394 | * @param array $notify - Массив используемых нотификацией со следующими ключами: 395 | * string notify_by_sms - За какое кол-во часов напоминанить по смс о записи (0 если не нужно) 396 | * string notify_by_email - За какое кол-во часов напоминанить по email о записи (0 если не нужно) 397 | * @param string $comment - Комментарий к записи 398 | * @param string $apiId - Внешний идентификатор записи 399 | * @return array 400 | * @access public 401 | * @see http://docs.yclients.apiary.io/#reference/-/8/0 402 | * @throws YclientsException 403 | */ 404 | public function postBookRecord( 405 | $companyId, 406 | array $person, 407 | array $appointments, 408 | $code = null, 409 | array $notify = null, 410 | $comment = null, 411 | $apiId = null 412 | ) { 413 | $parameters = []; 414 | 415 | // проверим наличие обязательных параметров клиента 416 | if (!isset($person['phone'], $person['fullname'], $person['email'])) { 417 | throw new YclientsException('Клиент должен содержать все обязательные поля: phone, fullname, email.'); 418 | } 419 | 420 | $parameters = array_merge($parameters, $person); 421 | 422 | if (!count($appointments)) { 423 | throw new YclientsException('Должна быть хотя бы одна запись.'); 424 | } 425 | 426 | // проверим наличие обязательных параметров записей 427 | foreach ($appointments as $appointment) { 428 | if (!isset($appointment['id'], $appointment['staff_id'], $appointment['datetime'])) { 429 | throw new YclientsException('Запись должна содержать все обязательные поля: id, staff_id, datetime.'); 430 | } 431 | } 432 | 433 | $parameters['appointments'] = $appointments; 434 | 435 | if ($notify) { 436 | if (isset($notify['notify_by_sms'])) { 437 | $parameters['notify_by_sms'] = $notify['notify_by_sms']; 438 | } 439 | if (isset($notify['notify_by_email'])) { 440 | $parameters['notify_by_email'] = $notify['notify_by_email']; 441 | } 442 | } 443 | 444 | if ($code !== null) { 445 | $parameters['code'] = $code; 446 | } 447 | 448 | if ($comment !== null) { 449 | $parameters['comment'] = $comment; 450 | } 451 | 452 | if ($apiId !== null) { 453 | $parameters['api_id'] = $apiId; 454 | } 455 | 456 | return $this->request('book_record/' . $companyId, $parameters, self::METHOD_POST); 457 | } 458 | 459 | /** 460 | * Авторизоваться по номеру телефона и коду 461 | * 462 | * @param string $phone - Телефон, на который будет отправлен код вида 79161005050 463 | * @param string $code - Код подтверждения номера телефона, высланный по смс 464 | * @return array 465 | * @access public 466 | * @see http://docs.yclients.apiary.io/#reference/1/0/0 467 | * @throws YclientsException 468 | */ 469 | public function postUserAuth($phone, $code) 470 | { 471 | $parameters = [ 472 | 'phone' => $phone, 473 | 'code' => $code, 474 | ]; 475 | 476 | return $this->request('user/auth', $parameters, self::METHOD_POST); 477 | } 478 | 479 | /** 480 | * Получить записи пользователя 481 | * 482 | * @param integer $recordId - ID записи, достаточно для удаления записи если пользователь 483 | * авторизован, получить можно из ответа bookRecord() 484 | * @param string $recordHash - HASH записи, обязательно для удаления записи если пользователь 485 | * не авторизован, получить можно из ответа bookRecord() 486 | * @param string $userToken - токен для авторизации пользователя, обязательный, если $recordHash не указан 487 | * @return array 488 | * @access public 489 | * @see http://docs.yclients.apiary.io/#reference/1/1/0 490 | * @throws YclientsException 491 | */ 492 | public function getUserRecords($recordId, $recordHash = null, $userToken = null) 493 | { 494 | if (!$recordHash && !$userToken) { 495 | throw new YclientsException('getUserRecords() требует обязательный 2-ой или 3-й аргумент'); 496 | // trigger_error('getUserRecords() expected Argument 2 or Argument 3 required', E_USER_WARNING); 497 | } 498 | 499 | return $this->request('user/records/' . $recordId . '/' . $recordHash, [], self::METHOD_GET, $userToken ?: true); 500 | } 501 | 502 | /** 503 | * Удалить записи пользователя 504 | * 505 | * @param integer $recordId - ID записи, достаточно для удаления записи если пользователь 506 | * авторизован, получить можно из ответа bookRecord() 507 | * @param string $recordHash - HASH записи, обязательно для удаления записи если пользователь 508 | * не авторизован, получить можно из ответа bookRecord() 509 | * @param string $userToken - Токен для авторизации пользователя, обязательный, если $recordHash не указан 510 | * @return array 511 | * @access public 512 | * @see http://docs.yclients.apiary.io/#reference/1/1/1 513 | * @throws YclientsException 514 | */ 515 | public function deleteUserRecords($recordId, $recordHash = null, $userToken = null) 516 | { 517 | if (!$recordHash && !$userToken) { 518 | throw new YclientsException('deleteUserRecords() требует обязательный 2-ой или 3-й аргумент'); 519 | // trigger_error('deleteUserRecords() expected Argument 2 or Argument 3 required', E_USER_WARNING); 520 | } 521 | 522 | return $this->request('user/records/' . $recordId . '/' . $recordHash, [], self::METHOD_DELETE, $userToken ?: true); 523 | } 524 | 525 | /** 526 | * Получить список доступных сетей салонов 527 | * @param string $userToken - Токен для авторизации пользователя, обязательный 528 | * @return array 529 | * @access public 530 | * @see http://docs.yclients.apiary.io/#reference/33/0/0 531 | * @throws YclientsException 532 | */ 533 | public function getGroups($userToken) 534 | { 535 | return $this->request('groups', [], self::METHOD_GET, $userToken); 536 | } 537 | 538 | /** 539 | * Получить основные показатели компании. 540 | * 541 | * @param string $companyId Идентификатор компании, обязательный. 542 | * @param string $dateFrom Дата начала анализируемого периода, обязательный. 543 | * @param string $dateTo Дата окончания анализируемого периода (включается в отчет), обязательный. 544 | * @param string $userToken Токен для авторизации пользователя, обязательный. 545 | * 546 | * @return array 547 | * 548 | * @see https://developers.yclients.com/ru/#tag/Analitika/paths/~1company~1%7Bcompany_id%7D~1analytics~1overall~1/get 549 | * 550 | * @throws YclientsException 551 | */ 552 | public function getCompanyAnalytics($companyId, $dateFrom, $dateTo, $userToken) 553 | { 554 | if (!$companyId) { 555 | throw new YclientsException('getAnalytics() требует ID компании'); 556 | } 557 | 558 | if (empty($userToken)) { 559 | throw new YclientsException('getAnalytics() требует авторизации по токену пользователя'); 560 | } 561 | 562 | $parameters = [ 563 | 'date_from' => $dateFrom, 564 | 'date_to' => $dateTo, 565 | ]; 566 | 567 | return $this->request( 568 | sprintf('company/%s/analytics/overall/', $companyId), 569 | $parameters, 570 | self::METHOD_GET, 571 | $userToken 572 | ); 573 | } 574 | 575 | /** 576 | * Получить список компаний 577 | * 578 | * @param integer $groupId - ID сети компаний 579 | * @param bool $active - Если нужно получить только активные для онлайн-записи компании 580 | * @param bool $moderated - Если нужно получить только прошедшие модерацию компании 581 | * @param bool $forBooking - Если нужно получить поле next_slot по каждой компании 582 | * @param bool $my - Если нужно компании, на управление которыми пользователь имеет права ($userToken тогда обязательно) 583 | * @param string $userToken - Токен для авторизации пользователя, обязательный, если $my указан 584 | * @return array 585 | * @access public 586 | * @see http://docs.yclients.apiary.io/#reference/2/0/0 587 | * @throws YclientsException 588 | */ 589 | public function getCompanies( 590 | $groupId = null, 591 | $active = null, 592 | $moderated = null, 593 | $forBooking = null, 594 | $my = null, 595 | $userToken = null 596 | ) { 597 | if ($my && !$userToken) { 598 | throw new YclientsException('getCompanies() требует обязательный 6-ой аргумент, если установле 5-й аргумент'); 599 | // trigger_error('getCompanies() expected Argument 6 if set Argument 5', E_USER_WARNING); 600 | } 601 | 602 | $parameters = []; 603 | 604 | if ($groupId !== null) { 605 | $parameters['group_id'] = $groupId; 606 | } 607 | 608 | if ($active !== null) { 609 | $parameters['active'] = $active; 610 | } 611 | 612 | if ($moderated !== null) { 613 | $parameters['moderated'] = $moderated; 614 | } 615 | 616 | if ($forBooking !== null) { 617 | $parameters['forBooking'] = $forBooking; 618 | } 619 | 620 | if ($my !== null) { 621 | $parameters['my'] = $my; 622 | } 623 | 624 | return $this->request('companies', $parameters, self::METHOD_GET, $userToken ?: true); 625 | } 626 | 627 | /** 628 | * Создать компанию 629 | * 630 | * @param array $fields - Остальные необязательные поля для создания компании 631 | * @param string $userToken - Токен для авторизации пользователя 632 | * @return array 633 | * @access public 634 | * @see http://docs.yclients.apiary.io/#reference/2/0/1 635 | * @throws YclientsException 636 | */ 637 | public function postCompany(array $fields, $userToken) 638 | { 639 | if (!isset($fields['title'])) { 640 | throw new YclientsException('Для создании компании обязательно название компании.'); 641 | } 642 | 643 | return $this->request('companies', $fields, self::METHOD_POST, $userToken); 644 | } 645 | 646 | /** 647 | * Получить компанию 648 | * 649 | * @param integer $id 650 | * @return array 651 | * @access public 652 | * @see http://docs.yclients.apiary.io/#reference/2/1/0 653 | * @throws YclientsException 654 | */ 655 | public function getCompany($id) 656 | { 657 | return $this->request('company/' . $id); 658 | } 659 | 660 | /** 661 | * Изменить компанию 662 | * 663 | * @param integer $id 664 | * @param array $fields - Остальные необязательные поля для создания компании 665 | * @param string $userToken - Токен для авторизации пользователя 666 | * @return array 667 | * @access public 668 | * @see http://docs.yclients.apiary.io/#reference/2/1/1 669 | * @throws YclientsException 670 | */ 671 | public function putCompany($id, array $fields, $userToken) 672 | { 673 | return $this->request('company/' . $id, $fields, self::METHOD_PUT, $userToken); 674 | } 675 | 676 | /** 677 | * Удалить компанию 678 | * 679 | * @param integer $id 680 | * @return array 681 | * @access public 682 | * @see http://docs.yclients.apiary.io/#reference/2/1/2 683 | * @throws YclientsException 684 | */ 685 | public function deleteCompany($id) 686 | { 687 | return $this->request('company/' . $id, [], self::METHOD_DELETE); 688 | } 689 | 690 | /** 691 | * Получить список категорий услуг 692 | * 693 | * @param integer $companyId - ID компании 694 | * @param integer $categoryId - ID категории услуг 695 | * @param integer $staffId - ID сотрудника (для получения категорий, привязанных к сотруднику) 696 | * @return array 697 | * @access public 698 | * @see http://docs.yclients.apiary.io/#reference/3/0/0 699 | * @throws YclientsException 700 | */ 701 | public function getServiceCategories($companyId, $categoryId = null, $staffId = null) 702 | { 703 | $parameters = []; 704 | 705 | if ($staffId !== null) { 706 | $parameters['staff_id'] = $staffId; 707 | } 708 | 709 | return $this->request('service_categories/' . $companyId . '/' . $categoryId, $parameters); 710 | } 711 | 712 | /** 713 | * Создать категорию услуг 714 | * 715 | * @param integer $companyId - ID компании 716 | * @param integer $categoryId - ID категории услуг 717 | * @param array $fields - Обязательные поля для категории со следующими полями: 718 | * string title - Название категории 719 | * integer api_id - Внешний идентификатор записи 720 | * integer weight 721 | * array staff 722 | * @param string $userToken - Токен для авторизации пользователя 723 | * @return array 724 | * @access public 725 | * @see http://docs.yclients.apiary.io/#reference/3/0/1 726 | * @throws YclientsException 727 | */ 728 | public function postServiceCategories($companyId, $categoryId, $fields, $userToken) 729 | { 730 | return $this->request('service_categories/' . $companyId . '/' . $categoryId, $fields, self::METHOD_POST, $userToken); 731 | } 732 | 733 | /** 734 | * Получить категорию услуг 735 | * 736 | * @param integer $companyId - ID компании 737 | * @param integer $categoryId - ID категории услуг 738 | * @return array 739 | * @access public 740 | * @see http://docs.yclients.apiary.io/#reference/3/1/0 741 | * @throws YclientsException 742 | */ 743 | public function getServiceCategory($companyId, $categoryId) 744 | { 745 | return $this->request('service_category/' . $companyId . '/' . $categoryId); 746 | } 747 | 748 | /** 749 | * Изменить категорию услуг 750 | * 751 | * @param integer $companyId - ID компании 752 | * @param integer $categoryId - ID категории услуг 753 | * @param array $fields - Обязательные поля для категории со следующими полями: 754 | * string title - Название категории 755 | * integer weight 756 | * array staff 757 | * @param string $userToken - Токен для авторизации пользователя 758 | * @return array 759 | * @access public 760 | * @see http://docs.yclients.apiary.io/#reference/3/1/1 761 | * @throws YclientsException 762 | */ 763 | public function putServiceCategory($companyId, $categoryId, $fields, $userToken) 764 | { 765 | return $this->request('service_category/' . $companyId . '/' . $categoryId, $fields, self::METHOD_PUT, $userToken); 766 | } 767 | 768 | /** 769 | * Удалить категорию услуг 770 | * 771 | * @param integer $companyId - ID компании 772 | * @param integer $categoryId - ID категории услуг 773 | * @param string $userToken - Токен для авторизации пользователя 774 | * @return array 775 | * @access public 776 | * @see http://docs.yclients.apiary.io/#reference/3/1/2 777 | * @throws YclientsException 778 | */ 779 | public function deleteServiceCategory($companyId, $categoryId, $userToken) 780 | { 781 | return $this->request('service_category/' . $companyId . '/' . $categoryId, [], self::METHOD_DELETE, $userToken); 782 | } 783 | 784 | /** 785 | * Получить список услуг / конкретную услугу 786 | * 787 | * @param integer $companyId - ID компании 788 | * @param integer $serviceId - ID услуги, если нужно работать с конкретной услугой 789 | * @param integer $staffId - ID сотрудника, если нужно отфильтровать по сотруднику 790 | * @param integer $categoryId - ID категории, если нужно отфильтровать по категории 791 | * @return array 792 | * @access public 793 | * @see http://docs.yclients.apiary.io/#reference/4/0// 794 | * @throws YclientsException 795 | */ 796 | public function getServices($companyId, $serviceId = null, $staffId = null, $categoryId = null) 797 | { 798 | $parameters = []; 799 | 800 | if ($staffId !== null) { 801 | $parameters['staff_id'] = $staffId; 802 | } 803 | 804 | if ($categoryId !== null) { 805 | $parameters['category_id'] = $categoryId; 806 | } 807 | 808 | return $this->request('services/' . $companyId . '/' . $serviceId, $parameters); 809 | } 810 | 811 | /** 812 | * Создать услугу 813 | * 814 | * @param integer $companyId - ID компании 815 | * @param integer $serviceId - ID услуги 816 | * @param string $title - Название услуги 817 | * @param integer $categoryId - ID категории услуг 818 | * @param string $userToken - Токен для авторизации пользователя 819 | * @param array $fields - Остальные необязательные поля для услуги 820 | * @return array 821 | * @access public 822 | * @see http://docs.yclients.apiary.io/#reference/4/0/0 823 | * @throws YclientsException 824 | */ 825 | public function postServices($companyId, $serviceId, $categoryId, $title, $userToken, array $fields = null) 826 | { 827 | $parameters = [ 828 | 'category_id' => $categoryId, 829 | 'title' => $title, 830 | ]; 831 | 832 | $parameters = array_merge($parameters, $fields); 833 | 834 | return $this->request('services/' . $companyId . '/' . $serviceId, $parameters, self::METHOD_POST, $userToken); 835 | } 836 | 837 | /** 838 | * Изменить услугу 839 | * 840 | * @param integer $companyId - ID компании 841 | * @param integer $serviceId - ID услуги 842 | * @param string $title - Название услуги 843 | * @param integer $categoryId - ID категории услуг 844 | * @param string $userToken - Токен для авторизации пользователя 845 | * @param array $fields - Остальные необязательные поля для услуги 846 | * @return array 847 | * @access public 848 | * @see http://docs.yclients.apiary.io/#reference/4/0/1 849 | * @throws YclientsException 850 | */ 851 | public function putServices($companyId, $serviceId, $categoryId, $title, $userToken, array $fields = null) 852 | { 853 | $parameters = [ 854 | 'category_id' => $categoryId, 855 | 'title' => $title, 856 | ]; 857 | 858 | $parameters = array_merge($parameters, $fields); 859 | 860 | return $this->request('services/' . $companyId . '/' . $serviceId, $parameters, self::METHOD_PUT, $userToken); 861 | } 862 | 863 | /** 864 | * Удалить услугу 865 | * 866 | * @param integer $companyId - ID компании 867 | * @param integer $serviceId - ID услуги 868 | * @param string $userToken - Токен для авторизации пользователя 869 | * @return array 870 | * @access public 871 | * @see http://docs.yclients.apiary.io/#reference/4/0/2 872 | * @throws YclientsException 873 | */ 874 | public function deleteServices($companyId, $serviceId, $userToken) 875 | { 876 | return $this->request('services/' . $companyId . '/' . $serviceId, [], self::METHOD_DELETE, $userToken); 877 | } 878 | 879 | /** 880 | * Получить список акций / конкретную акцию 881 | * 882 | * @param integer $companyId - ID компании 883 | * @param integer $eventId - ID услуги, если нужно работать с конкретной услугой. 884 | * @return array 885 | * @access public 886 | * @see http://docs.yclients.apiary.io/#reference/5// 887 | * @throws YclientsException 888 | */ 889 | public function getEvents($companyId, $eventId = null) 890 | { 891 | return $this->request('events/' . $companyId . '/' . $eventId); 892 | } 893 | 894 | /** 895 | * Получить список сотрудников / конкретного сотрудника 896 | * 897 | * @param integer $companyId - ID компании 898 | * @param integer $staffId - ID сотрудника, если нужно работать с конкретным сотрудником 899 | * @return array 900 | * @access public 901 | * @see http://docs.yclients.apiary.io/#reference/6// 902 | * @throws YclientsException 903 | */ 904 | public function getStaff($companyId, $staffId = null) 905 | { 906 | return $this->request('staff/' . $companyId . '/' . $staffId); 907 | } 908 | 909 | /** 910 | * Добавить нового сотрудника 911 | * 912 | * @param integer $companyId - ID компании 913 | * @param integer $staffId - ID сотрудника 914 | * @param string $name - Имя сотрудника 915 | * @param string $userToken - Токен для авторизации пользователя 916 | * @param array $fields - Остальные необязательные поля для сотрудника 917 | * @return array 918 | * @access public 919 | * @see http://docs.yclients.apiary.io/#reference/6/0/0 920 | * @throws YclientsException 921 | */ 922 | public function postStaff($companyId, $staffId, $name, $userToken, array $fields = null) 923 | { 924 | $parameters = [ 925 | 'name' => $name, 926 | ]; 927 | 928 | $parameters = array_merge($parameters, $fields); 929 | 930 | return $this->request('staff/' . $companyId . '/' . $staffId, $parameters, self::METHOD_POST, $userToken); 931 | } 932 | 933 | /** 934 | * Изменить сотрудника 935 | * 936 | * @param integer $companyId - ID компании 937 | * @param integer $staffId - ID сотрудника 938 | * @param array $fields - Остальные необязательные поля для услуги 939 | * @param string $userToken - Токен для авторизации пользователя 940 | * @return array 941 | * @access public 942 | * @see http://docs.yclients.apiary.io/#reference/6/0/1 943 | * @throws YclientsException 944 | */ 945 | public function putStaff($companyId, $staffId, array $fields, $userToken) 946 | { 947 | return $this->request('staff/' . $companyId . '/' . $staffId, $fields, self::METHOD_PUT, $userToken); 948 | } 949 | 950 | /** 951 | * Удалить сотрудника 952 | * 953 | * @param integer $companyId - ID компании 954 | * @param integer $staffId - ID сотрудника 955 | * @param string $userToken - Токен для авторизации пользователя 956 | * @return array 957 | * @access public 958 | * @see http://docs.yclients.apiary.io/#reference/6/0/2 959 | * @throws YclientsException 960 | */ 961 | public function deleteStaff($companyId, $staffId, $userToken) 962 | { 963 | return $this->request('staff/' . $companyId . '/' . $staffId, [], self::METHOD_DELETE, $userToken); 964 | } 965 | 966 | /** 967 | * Получить список клиентов 968 | * 969 | * @param integer $companyId - ID компании 970 | * @param string $userToken - Токен для авторизации пользователя 971 | * @param string $fullname 972 | * @param string $phone 973 | * @param string $email 974 | * @param string $page 975 | * @param string $count 976 | * @return array 977 | * @access public 978 | * @see http://docs.yclients.apiary.io/#reference/7/0/0 979 | * @throws YclientsException 980 | */ 981 | public function getClients( 982 | $companyId, 983 | $userToken, 984 | $fullname = null, 985 | $phone = null, 986 | $email = null, 987 | $page = null, 988 | $count = null 989 | ) { 990 | $parameters = []; 991 | 992 | if ($fullname !== null) { 993 | $parameters['fullname'] = $fullname; 994 | } 995 | 996 | if ($phone !== null) { 997 | $parameters['phone'] = $phone; 998 | } 999 | 1000 | if ($email !== null) { 1001 | $parameters['email'] = $email; 1002 | } 1003 | 1004 | if ($page !== null) { 1005 | $parameters['page'] = $page; 1006 | } 1007 | 1008 | if ($count !== null) { 1009 | $parameters['count'] = $count; 1010 | } 1011 | 1012 | return $this->request('clients/' . $companyId, $parameters, self::METHOD_GET, $userToken); 1013 | } 1014 | 1015 | /** 1016 | * Добавить клиента 1017 | * 1018 | * @param integer $companyId - ID компании 1019 | * @param string $name - Имя клиента 1020 | * @param integer $phone - Телефон клиента 1021 | * @param string $userToken - Токен для авторизации пользователя 1022 | * @param array $fields - Остальные необязательные поля для клиента 1023 | * @return array 1024 | * @access public 1025 | * @see http://docs.yclients.apiary.io/#reference/7/0/1 1026 | * @throws YclientsException 1027 | */ 1028 | public function postClients($companyId, $name, $phone, $userToken, array $fields = []) 1029 | { 1030 | $parameters = [ 1031 | 'name' => $name, 1032 | 'phone' => $phone, 1033 | ]; 1034 | 1035 | $parameters = array_merge($parameters, $fields); 1036 | 1037 | return $this->request('clients/' . $companyId, $parameters, self::METHOD_POST, $userToken); 1038 | } 1039 | 1040 | /** 1041 | * Получить клиента 1042 | * 1043 | * @param integer $companyId - ID компании 1044 | * @param integer $id - ID клиента 1045 | * @param string $userToken - Токен для авторизации пользователя 1046 | * @return array 1047 | * @access public 1048 | * @see http://docs.yclients.apiary.io/#reference/7/1/0 1049 | * @throws YclientsException 1050 | */ 1051 | public function getClient($companyId, $id, $userToken) 1052 | { 1053 | return $this->request('client/' . $companyId . '/' . $id, [], self::METHOD_GET, $userToken); 1054 | } 1055 | 1056 | /** 1057 | * Редактировать клиента 1058 | * 1059 | * @param integer $companyId - ID компании 1060 | * @param integer $id - ID клиента 1061 | * @param string $userToken - Токен для авторизации пользователя 1062 | * @param array $fields 1063 | * @return array 1064 | * @access public 1065 | * @see http://docs.yclients.apiary.io/#reference/7/1/1 1066 | * @throws YclientsException 1067 | */ 1068 | public function putClient($companyId, $id, $userToken, array $fields) 1069 | { 1070 | return $this->request('client/' . $companyId . '/' . $id, $fields, self::METHOD_PUT, $userToken); 1071 | } 1072 | 1073 | /** 1074 | * Удалить клиента 1075 | * 1076 | * @param integer $companyId - ID компании 1077 | * @param integer $id - ID клиента 1078 | * @param string $userToken - Токен для авторизации пользователя 1079 | * @return array 1080 | * @access public 1081 | * @see http://docs.yclients.apiary.io/#reference/7/1/2 1082 | * @throws YclientsException 1083 | */ 1084 | public function deleteClient($companyId, $id, $userToken) 1085 | { 1086 | return $this->request('client/' . $companyId . '/' . $id, [], self::METHOD_DELETE, $userToken); 1087 | } 1088 | 1089 | /** 1090 | * Получить список записей 1091 | * 1092 | * @param integer $companyId - ID компании 1093 | * @param string $userToken - Токен для авторизации пользователя 1094 | * @param integer $page 1095 | * @param integer $count 1096 | * @param integer $staffId 1097 | * @param integer $clientId 1098 | * @param \DateTime $startDate 1099 | * @param \DateTime $endDate 1100 | * @param \DateTime $cStartDate 1101 | * @param \DateTime $cEndDate 1102 | * @param \DateTime $changedAfter 1103 | * @param \DateTime $changedBefore 1104 | * @return array 1105 | * @access public 1106 | * @see http://docs.yclients.apiary.io/#reference/8/0/0 1107 | * @throws YclientsException 1108 | */ 1109 | public function getRecords( 1110 | $companyId, 1111 | $userToken, 1112 | $page = null, 1113 | $count = null, 1114 | $staffId = null, 1115 | $clientId = null, 1116 | \DateTime $startDate = null, 1117 | \DateTime $endDate = null, 1118 | \DateTime $cStartDate = null, 1119 | \DateTime $cEndDate = null, 1120 | \DateTime $changedAfter = null, 1121 | \DateTime $changedBefore = null 1122 | ) { 1123 | $parameters = []; 1124 | 1125 | if ($page !== null) { 1126 | $parameters['page'] = $page; 1127 | } 1128 | 1129 | if ($count !== null) { 1130 | $parameters['count'] = $count; 1131 | } 1132 | 1133 | if ($staffId !== null) { 1134 | $parameters['staff_id'] = $staffId; 1135 | } 1136 | 1137 | if ($clientId !== null) { 1138 | $parameters['client_id'] = $clientId; 1139 | } 1140 | 1141 | if ($startDate !== null) { 1142 | $parameters['start_date'] = $startDate->format('Y-m-d'); 1143 | } 1144 | 1145 | if ($endDate !== null) { 1146 | $parameters['end_date'] = $endDate->format('Y-m-d'); 1147 | } 1148 | 1149 | if ($cStartDate !== null) { 1150 | $parameters['c_start_date'] = $cStartDate->format('Y-m-d'); 1151 | } 1152 | 1153 | if ($cEndDate !== null) { 1154 | $parameters['c_end_date'] = $cEndDate->format('Y-m-d'); 1155 | } 1156 | 1157 | if ($changedAfter !== null) { 1158 | $parameters['changed_after'] = $changedAfter->format(\DateTime::ISO8601); 1159 | } 1160 | 1161 | if ($changedBefore !== null) { 1162 | $parameters['changed_before'] = $changedBefore->format(\DateTime::ISO8601); 1163 | } 1164 | 1165 | return $this->request('records/' . $companyId, $parameters, self::METHOD_GET, $userToken); 1166 | } 1167 | 1168 | /** 1169 | * Создать новую запись 1170 | * 1171 | * @param integer $companyId - ID компании 1172 | * @param string $userToken - Токен для авторизации пользователя 1173 | * @param integer $staffId 1174 | * @param array $services 1175 | * @param array $client 1176 | * @param \DateTime $datetime 1177 | * @param integer $seanceLength 1178 | * @param bool $saveIfBusy 1179 | * @param bool $sendSms 1180 | * @param string $comment 1181 | * @param integer $smsRemainHours 1182 | * @param integer $emailRemainHours 1183 | * @param integer $apiId 1184 | * @param integer $attendance 1185 | * @return array 1186 | * @access public 1187 | * @see http://docs.yclients.apiary.io/#reference/8/0/1 1188 | * @throws YclientsException 1189 | */ 1190 | public function postRecords( 1191 | $companyId, 1192 | $userToken, 1193 | $staffId, 1194 | $services, 1195 | $client, 1196 | \DateTime $datetime, 1197 | $seanceLength, 1198 | $saveIfBusy, 1199 | $sendSms, 1200 | $comment = null, 1201 | $smsRemainHours = null, 1202 | $emailRemainHours = null, 1203 | $apiId = null, 1204 | $attendance = null 1205 | ) { 1206 | $parameters = []; 1207 | 1208 | if ($staffId !== null) { 1209 | $parameters['staff_id'] = $staffId; 1210 | } 1211 | 1212 | if ($services !== null) { 1213 | $parameters['services'] = $services; 1214 | } 1215 | 1216 | if ($client !== null) { 1217 | $parameters['client'] = $client; 1218 | } 1219 | 1220 | if ($datetime !== null) { 1221 | $parameters['datetime'] = $datetime->format(\DateTime::ISO8601); 1222 | } 1223 | 1224 | if ($seanceLength !== null) { 1225 | $parameters['seance_length'] = $seanceLength; 1226 | } 1227 | 1228 | if ($saveIfBusy !== null) { 1229 | $parameters['save_if_busy'] = $saveIfBusy; 1230 | } 1231 | 1232 | if ($sendSms !== null) { 1233 | $parameters['send_sms'] = $sendSms; 1234 | } 1235 | 1236 | if ($comment !== null) { 1237 | $parameters['comment'] = $comment; 1238 | } 1239 | 1240 | if ($smsRemainHours !== null) { 1241 | $parameters['sms_remain_hours'] = $smsRemainHours; 1242 | } 1243 | 1244 | if ($emailRemainHours !== null) { 1245 | $parameters['email_remain_hours'] = $emailRemainHours; 1246 | } 1247 | 1248 | if ($apiId !== null) { 1249 | $parameters['api_id'] = $apiId; 1250 | } 1251 | 1252 | if ($attendance !== null) { 1253 | $parameters['attendance'] = $attendance; 1254 | } 1255 | 1256 | return $this->request('records/' . $companyId, $parameters, self::METHOD_POST, $userToken); 1257 | } 1258 | 1259 | /** 1260 | * Получить запись 1261 | * 1262 | * @param integer $companyId - ID компании 1263 | * @param integer $recordId 1264 | * @param string $userToken - Токен для авторизации пользователя 1265 | * @return array 1266 | * @access public 1267 | * @see http://docs.yclients.apiary.io/#reference/8/1/0 1268 | * @throws YclientsException 1269 | */ 1270 | public function getRecord($companyId, $recordId, $userToken) 1271 | { 1272 | return $this->request('record/' . $companyId . '/' . $recordId, [], self::METHOD_GET, $userToken); 1273 | } 1274 | 1275 | /** 1276 | * Изменить запись 1277 | * 1278 | * @param integer $companyId - ID компании 1279 | * @param integer $recordId 1280 | * @param string $userToken - Токен для авторизации пользователя 1281 | * @param array $fields 1282 | * @return array 1283 | * @access public 1284 | * @see http://docs.yclients.apiary.io/#reference/8/1/1 1285 | * @throws YclientsException 1286 | */ 1287 | public function putRecord($companyId, $recordId, $userToken, array $fields) 1288 | { 1289 | return $this->request('record/' . $companyId . '/' . $recordId, $fields, self::METHOD_PUT, $userToken); 1290 | } 1291 | 1292 | /** 1293 | * Удалить запись 1294 | * 1295 | * @param integer $companyId - ID компании 1296 | * @param integer $recordId 1297 | * @param string $userToken - Токен для авторизации пользователя 1298 | * @return array 1299 | * @access public 1300 | * @see http://docs.yclients.apiary.io/#reference/8/1/2 1301 | * @throws YclientsException 1302 | */ 1303 | public function deleteRecord($companyId, $recordId, $userToken) 1304 | { 1305 | return $this->request('record/' . $companyId . '/' . $recordId, [], self::METHOD_DELETE, $userToken); 1306 | } 1307 | 1308 | /** 1309 | * Изменить расписание работы сотрудника 1310 | * 1311 | * @param integer $companyId - ID компании 1312 | * @param integer $staffId 1313 | * @param string $userToken - Токен для авторизации пользователя 1314 | * @param array $fields 1315 | * @return array 1316 | * @access public 1317 | * @see http://docs.yclients.apiary.io/#reference/9/0 1318 | * @throws YclientsException 1319 | */ 1320 | public function putSchedule($companyId, $staffId, $userToken, $fields) 1321 | { 1322 | return $this->request('schedule/' . $companyId . '/' . $staffId, $fields, self::METHOD_PUT, $userToken); 1323 | } 1324 | 1325 | /** 1326 | * Получить расписание работы сотрудника 1327 | * 1328 | * @param integer $companyId - ID компании 1329 | * @param integer $staffId 1330 | * @param string $startDate 1331 | * @param string $endDate 1332 | * @param string $userToken - Токен для авторизации пользователя 1333 | * @return array 1334 | * @access public 1335 | * @see https://yclients.docs.apiary.io/#reference/12/1 1336 | * @throws YclientsException 1337 | */ 1338 | public function getSchedule($companyId, $staffId, $startDate, $endDate, $userToken) 1339 | { 1340 | return $this->request('schedule/' . $companyId . '/' . $staffId . '/' . $startDate . '/'. $endDate, [], self::METHOD_GET, $userToken); 1341 | } 1342 | 1343 | /** 1344 | * Получить список дат для журнала 1345 | * 1346 | * @param integer $companyId - ID компании 1347 | * @param \DateTime $date 1348 | * @param integer $staffId 1349 | * @param string $userToken - Токен для авторизации пользователя 1350 | * @return array 1351 | * @access public 1352 | * @see http://docs.yclients.apiary.io/#reference/10/0/0 1353 | * @throws YclientsException 1354 | */ 1355 | public function getTimetableDates($companyId, \DateTime $date, $staffId, $userToken) 1356 | { 1357 | $parameters = []; 1358 | 1359 | if ($staffId !== null) { 1360 | $parameters['staff_id'] = $staffId; 1361 | } 1362 | 1363 | return $this->request('timetable/dates/' . $companyId . '/' . $date->format('Y-m-d'), $parameters, self::METHOD_GET, $userToken); 1364 | } 1365 | 1366 | /** 1367 | * Получить список сеансов для журнала 1368 | * 1369 | * @param integer $companyId - ID компании 1370 | * @param \DateTime $date 1371 | * @param integer $staffId 1372 | * @param string $userToken - Токен для авторизации пользователя 1373 | * @return array 1374 | * @access public 1375 | * @see http://docs.yclients.apiary.io/#reference/11/0/0 1376 | * @throws YclientsException 1377 | */ 1378 | public function getTimetableSeances($companyId, \DateTime $date, $staffId, $userToken) 1379 | { 1380 | return $this->request('timetable/seances/' . $companyId . '/' . $staffId . '/' . $date->format('Y-m-d'), [], self::METHOD_GET, $userToken); 1381 | } 1382 | 1383 | /** 1384 | * Получить комментарии 1385 | * 1386 | * @param integer $companyId - ID компании 1387 | * @param string $userToken - Токен для авторизации пользователя 1388 | * @param \DateTime $startDate 1389 | * @param \DateTime $endDate 1390 | * @param integer $staffId 1391 | * @param integer $rating 1392 | * @return array 1393 | * @access public 1394 | * @see http://docs.yclients.apiary.io/#reference/12/0/0 1395 | * @throws YclientsException 1396 | */ 1397 | public function getComments( 1398 | $companyId, 1399 | $userToken, 1400 | \DateTime $startDate = null, 1401 | \DateTime $endDate = null, 1402 | $staffId = null, 1403 | $rating = null 1404 | ) { 1405 | $parameters = []; 1406 | 1407 | if ($startDate !== null) { 1408 | $parameters['start_date'] = $startDate->format('Y-m-d'); 1409 | } 1410 | 1411 | if ($endDate !== null) { 1412 | $parameters['end_date'] = $endDate->format('Y-m-d'); 1413 | } 1414 | 1415 | if ($staffId !== null) { 1416 | $parameters['staff_id'] = $staffId; 1417 | } 1418 | 1419 | if ($rating !== null) { 1420 | $parameters['rating'] = $rating; 1421 | } 1422 | 1423 | return $this->request('comments/' . $companyId, $parameters, self::METHOD_GET, $userToken); 1424 | } 1425 | 1426 | /** 1427 | * Получить пользователей компании 1428 | * 1429 | * @param integer $companyId - ID компании 1430 | * @param string $userToken - Токен для авторизации пользователя 1431 | * @return array 1432 | * @access public 1433 | * @see http://docs.yclients.apiary.io/#reference/13/0/0 1434 | * @throws YclientsException 1435 | */ 1436 | public function getCompanyUsers($companyId, $userToken) 1437 | { 1438 | return $this->request('company_users/' . $companyId, [], self::METHOD_GET, $userToken); 1439 | } 1440 | 1441 | /** 1442 | * Получить кассы компании 1443 | * 1444 | * @param integer $companyId - ID компании 1445 | * @param string $userToken - Токен для авторизации пользователя 1446 | * @return array 1447 | * @access public 1448 | * @see http://docs.yclients.apiary.io/#reference/14/0/0 1449 | * @throws YclientsException 1450 | */ 1451 | public function getAccounts($companyId, $userToken) 1452 | { 1453 | return $this->request('accounts/' . $companyId, [], self::METHOD_GET, $userToken); 1454 | } 1455 | 1456 | /** 1457 | * Отправить SMS 1458 | * 1459 | * @param integer $companyId - ID компании 1460 | * @param string $userToken - Токен для авторизации пользователя 1461 | * @param integer[] $clientIds - ID клиентов 1462 | * @param string $text - Тест сообщения 1463 | * @return array 1464 | * @access public 1465 | * @see http://docs.yclients.apiary.io/#reference/14/0/0 1466 | * @throws YclientsException 1467 | */ 1468 | public function sendSMS($companyId, $userToken, $clientIds, $text) 1469 | { 1470 | $parameters = []; 1471 | $parameters['client_ids'] = $clientIds; 1472 | $parameters['text'] = $text; 1473 | 1474 | return $this->request('sms/clients/by_id/' . $companyId, $parameters, self::METHOD_POST, $userToken); 1475 | } 1476 | 1477 | /** 1478 | * Получить склады компании 1479 | * 1480 | * @param integer $companyId - ID компании 1481 | * @param string $userToken - Токен для авторизации пользователя 1482 | * @return array 1483 | * @access public 1484 | * @see http://docs.yclients.apiary.io/#reference/15/0/0 1485 | * @throws YclientsException 1486 | */ 1487 | public function getStorages($companyId, $userToken) 1488 | { 1489 | return $this->request('storages/' . $companyId, [], self::METHOD_GET, $userToken); 1490 | } 1491 | 1492 | /** 1493 | * Получить настройки уведомлений о событиях 1494 | * 1495 | * @param integer $companyId - ID компании 1496 | * @param string $userToken - Токен для авторизации пользователя 1497 | * @return array 1498 | * @access public 1499 | * @see http://docs.yclients.apiary.io/#reference/18/0/0 1500 | * @throws YclientsException 1501 | */ 1502 | public function getHooks($companyId, $userToken) 1503 | { 1504 | return $this->request('hooks_settings/' . $companyId, [], self::METHOD_GET, $userToken); 1505 | } 1506 | 1507 | /** 1508 | * Изменить настройки уведомлений о событиях 1509 | * 1510 | * @param integer $companyId - ID компании 1511 | * @param array $fields 1512 | * @param string $userToken - Токен для авторизации пользователя 1513 | * @return array 1514 | * @access public 1515 | * @see http://docs.yclients.apiary.io/#reference/18/0/1 1516 | * @throws YclientsException 1517 | */ 1518 | public function postHooks($companyId, $fields, $userToken) 1519 | { 1520 | if (!isset($fields['urls'])) { 1521 | throw new YclientsException('Не передан обязательный параметр urls'); 1522 | } 1523 | if (!isset($fields['active'])) { 1524 | throw new YclientsException('Не передан обязательный параметр active'); 1525 | } 1526 | return $this->request('hooks_settings/' . $companyId, $fields, self::METHOD_POST, $userToken); 1527 | } 1528 | } 1529 | -------------------------------------------------------------------------------- /src/Yclients/YclientsException.php: -------------------------------------------------------------------------------- 1 | tokenPartner) { 113 | throw new YclientsException('Не указан токен партнёра'); 114 | } 115 | 116 | $headers[] = 'Authorization: Bearer ' . $this->tokenPartner . (is_string($auth) ? ', User ' . $auth : ''); 117 | } 118 | 119 | return $this->requestCurl($url, $parameters, $method, $headers); 120 | } 121 | 122 | /** 123 | * Выполнение непосредственно запроса с помощью curl 124 | * 125 | * @param string $url 126 | * @param array $parameters 127 | * @param string $method 128 | * @param array $headers 129 | * @return array 130 | * @access protected 131 | * @throws YclientsException 132 | */ 133 | protected function requestCurl($url, $parameters = [], $method = 'GET', $headers = []) 134 | { 135 | // Увеличиваем счетчик числа отправленных запросов 136 | $this->requestCounter++; 137 | 138 | $ch = curl_init(); 139 | 140 | $jsonParameters = '{}'; 141 | if (count($parameters)) { 142 | if ($method === self::METHOD_GET) { 143 | $url .= '?' . http_build_query($parameters); 144 | } else { 145 | $jsonParameters = json_encode($parameters); 146 | if ($jsonParameters === false) { 147 | $code = json_last_error(); 148 | throw new YclientsException("Ошибка кодирования JSON ({$code}): " . print_r($parameters, true)); 149 | } 150 | curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonParameters); 151 | } 152 | } 153 | 154 | if ($method === self::METHOD_GET) { 155 | $this->debug("[{$this->requestCounter}] ===> GET {$url}"); 156 | } elseif ($method === self::METHOD_POST) { 157 | curl_setopt($ch, CURLOPT_POST, true); 158 | $this->debug("[{$this->requestCounter}] ===> POST {$url}" . PHP_EOL . $jsonParameters); 159 | } elseif ($method === self::METHOD_PUT) { 160 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, self::METHOD_PUT); 161 | $this->debug("[{$this->requestCounter}] ===> PUT {$url}" . PHP_EOL . $jsonParameters); 162 | } elseif ($method === self::METHOD_DELETE) { 163 | $this->debug("[{$this->requestCounter}] ===> DELETE: {$url}" . PHP_EOL . $jsonParameters); 164 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, self::METHOD_DELETE); 165 | } 166 | 167 | curl_setopt($ch, CURLOPT_URL, self::URL . '/' . $url); 168 | curl_setopt($ch, CURLOPT_FAILONERROR, false); 169 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 170 | curl_setopt($ch, CURLOPT_TIMEOUT, $this->curlTimeout); 171 | curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->curlConnectTimeout); 172 | curl_setopt($ch, CURLOPT_HEADER, false); 173 | 174 | // Включение проверки SSL-сертификата сервера YClients 175 | if ($this->verifySSLCerfificate) { 176 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); 177 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); 178 | if ($this->sslCertificateFile) { 179 | $sslCertificateFile = dirname(__FILE__) . DIRECTORY_SEPARATOR . $this->sslCertificateFile; 180 | curl_setopt($ch, CURLOPT_CAINFO, $sslCertificateFile); 181 | } 182 | } else { 183 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); 184 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); 185 | } 186 | 187 | if (count($headers)) { 188 | curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); 189 | } 190 | 191 | $result = $this->throttleCurl($ch); 192 | $deltaTime = sprintf('%0.4f', microtime(true) - $this->lastRequestTime); 193 | $code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE); 194 | $errno = curl_errno($ch); 195 | $error = curl_error($ch); 196 | curl_close($ch); 197 | 198 | // Проверка ошибок cURL 199 | if ($errno) { 200 | throw new YclientsException("Oшибка cURL ({$errno}): {$error}"); 201 | } 202 | 203 | // Если в ответе были переданы только заголовки без тела сообщения (204 No Content) 204 | if ($code === 204) { 205 | $this->debug( 206 | "[{$this->requestCounter}] <=== RESPONSE {$deltaTime}s ({$code})" . PHP_EOL . print_r($result, true) 207 | ); 208 | return null; 209 | } 210 | 211 | // Декодирование JSON ответа сервера 212 | $response = json_decode($result, true); 213 | $this->debug( 214 | "[{$this->requestCounter}] <=== RESPONSE {$deltaTime}s ({$code})" . PHP_EOL . print_r($response, true) 215 | ); 216 | if (is_null($response)) { 217 | $code = json_last_error(); 218 | throw new YclientsException("Ошибка декодирования JSON ({$code}): {$result}"); 219 | } 220 | 221 | // Если сообщение об ошибке в ответе сервера 222 | if (isset($response['errors'])) { 223 | throw new YclientsException( 224 | 'Ошибка: ' . print_r($response['errors'], true) . '. Request: ' . $jsonParameters 225 | ); 226 | } 227 | 228 | // Если сообщение об ошибке success:false в ответе сервера 229 | if (isset($response['success']) && ! $response['success']) { 230 | throw new YclientsException('Ошибка: ' . print_r($response, true) . '. Request: ' . $jsonParameters); 231 | } 232 | 233 | return $response; 234 | } 235 | 236 | /** 237 | * Загружает все сущности заданного типа 238 | * @param object $callback Анонимная функция для загрузки сущностей: $callback($page, $count) 239 | * $page - номер страницы, $count - число сущностей на странице 240 | * @return \Generator 241 | */ 242 | public function getAll($callback) :\Generator 243 | { 244 | $page = 1; 245 | 246 | while (true) { 247 | $response = $callback($page, $this->limitCount); 248 | $data = $response['data']; 249 | 250 | yield $response; 251 | 252 | if (count($data) < $this->limitCount) { 253 | break; 254 | } 255 | 256 | $page++; 257 | } 258 | } 259 | 260 | /** 261 | * Обеспечивает троттлинг запросов к YClients API 262 | * @param resource $curl 263 | * @return string|null 264 | */ 265 | protected function throttleCurl($curl) 266 | { 267 | if ($this->throttle > 0) { 268 | do { 269 | $usleep = (int) (1E6 * ($this->lastRequestTime + 1/$this->throttle - microtime(true))); 270 | if ($usleep <= 0) { 271 | break; 272 | } 273 | 274 | $throttleTime = sprintf('%0.4f', $usleep/1E6); 275 | $this->debug("[{$this->requestCounter}] ++++ THROTTLE ({$this->throttle}) {$throttleTime}s"); 276 | 277 | usleep($usleep); 278 | } while (false); 279 | } 280 | 281 | $this->lastRequestTime = microtime(true); 282 | 283 | $result = curl_exec($curl); 284 | 285 | return $result; 286 | } 287 | 288 | /** 289 | * Выводит отладочные сообщения 290 | * @param string $message 291 | * @return void 292 | */ 293 | // ------------------------------------------------------------------------ 294 | protected function debug(string $message = '') 295 | { 296 | if (! $this->debug) { 297 | return; 298 | } 299 | 300 | // Формируем строку времени логгирования 301 | $dateTime = \DateTime::createFromFormat('U.u', sprintf('%.f', microtime(true))); 302 | $timeZone = new \DateTimeZone(date_default_timezone_get()); 303 | $dateTime->setTimeZone($timeZone); 304 | $timeString = $dateTime->format('Y-m-d H:i:s,u P'); 305 | 306 | $uniqId = $this->getUniqId(); 307 | $message = "*** {$uniqId} [{$timeString}]" . PHP_EOL . $message . PHP_EOL . PHP_EOL; 308 | 309 | // Если лог файл не указан, то вывод в STDOUT 310 | if (empty($this->debugLogFile)) { 311 | echo $message . PHP_EOL; 312 | return; 313 | } 314 | 315 | // Формируем полное имя лог файла 316 | $debugLogFile = dirname(__FILE__) . DIRECTORY_SEPARATOR . $this->debugLogFile; 317 | $this->checkDir(dirname($debugLogFile)); 318 | 319 | // Записываем сообщение в лог файл 320 | if (! file_put_contents($debugLogFile, $message, FILE_APPEND|LOCK_EX)) { 321 | throw new YclientsException("Не удалось записать в лог файл {$debugLogFile}"); 322 | } 323 | } 324 | 325 | /** 326 | * Возвращает уникальное значение ID для метки в отладочных сообщениях 327 | * @param int $length Длина ID 328 | * @return string 329 | */ 330 | protected function getUniqId(int $length = 7) :string 331 | { 332 | if (! isset($this->uniqId)) { 333 | $this->uniqId = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyz"), 0, $length); 334 | } 335 | return $this->uniqId; 336 | } 337 | 338 | /** 339 | * Проверяет наличие каталога для сохранения файла и создает каталог при его отсутствии рекурсивно 340 | * @param string $directory Полный путь к каталогу 341 | * @return void 342 | */ 343 | protected function checkDir(string $directory) 344 | { 345 | // Выходим, если каталог уже есть (is_dir кешируется PHP) 346 | if (is_dir($directory)) { 347 | return; 348 | } 349 | 350 | // Создаем новый каталог рекурсивно 351 | if (!mkdir($directory, $mode = 0755, $recursive = true) && !is_dir($directory)) { 352 | throw new YclientsException("Не удалось рекурсивно создать каталог {$directory}"); 353 | } 354 | } 355 | } 356 | --------------------------------------------------------------------------------