diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..36d1495b --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +custom: ["https://boosty.to/bitrix24-php-sdk"] \ No newline at end of file diff --git a/.gitignore b/.gitignore index 7c3db918..f5140f0e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /.idea* +/app vendor composer.phar composer.lock diff --git a/CHANGELOG.md b/CHANGELOG.md index aff9d94a..12e933af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,71 @@ # bitrix24-php-sdk change log -## 2.0-alpha.6 — 7.02.2021 +## 2.0-alpha.7 — 8.08.2022 + +### Added + +* add new scope `Telephony` and services [add Telephony support](https://github.com/mesilov/bitrix24-php-sdk/issues/291) +* add new scope `UserConsent` and services [add UserConsent support](https://github.com/mesilov/bitrix24-php-sdk/issues/285) +* add new scope `Placements` and services [add Placements support](https://github.com/mesilov/bitrix24-php-sdk/issues/274) +* add new scope `IMOpenLines` and services [add IM Open Lines support](https://github.com/mesilov/bitrix24-php-sdk/issues/302) +* add in scope `CRM` new service `Leads` in scope «CRM» [add Leads support](https://github.com/mesilov/bitrix24-php-sdk/issues/282) +* add in scope `CRM` new service `Activity` in scope «CRM» [add Activity support](https://github.com/mesilov/bitrix24-php-sdk/issues/283) +* add in scope `CRM` for entity Deal method `Services\CRM\Deal\Service\Batch::update` batch update deals +* add in scope `CRM` for entity Contact method `Services\CRM\Contact\Service\Batch::delete` batch delete contacts +* add in scope `CRM` [read models](https://github.com/mesilov/bitrix24-php-sdk/issues/300) for activity `Services\CRM\Activity\ReadModel` + for activity types: `EmailFetcher`, `OpenLineFetcher`, `VoximplantFetcher`, `WebFormFetcher` +* add in scope «Main» new service `Events` [add incoming events support](https://github.com/mesilov/bitrix24-php-sdk/issues/296) +* add support Application level events: `ONAPPINSTALL` + and `ONAPPUNINSTALL` [add incoming events support](https://github.com/mesilov/bitrix24-php-sdk/issues/296) +* add support Application level event: `PortalDomainUrlChangedEvent` +* add method `Core\Batch::updateEntityItems` for [update items in batch mode](https://github.com/mesilov/bitrix24-php-sdk/issues/268) and + integration test +* add method to interface `Core\Contracts\BatchInterface::updateEntityItems` for update items in batch mode +* add in scope `Placements` service `Placement\Service\UserFieldType` for work with user fields embedding +* add in scope `Telephony` add events: `OnExternalCallBackStart`, `OnExternalCallStart`, `OnVoximplantCallEnd`, `OnVoximplantCallEnd` + , `OnVoximplantCallInit`, `OnVoximplantCallStart` see [add telephony events](https://github.com/mesilov/bitrix24-php-sdk/issues/304) +* add `ApplicationStatus` with application status codes description +* add fabric method `AccessToken::initFromPlacementRequest` when application init form placement request +* add fabric method `ApplicationProfile::initFromArray` when application profile stored in ENV-variables +* add `Bitrix24\SDK\Application\Requests\Placement\PlacementRequest` for application data from placements +* add fabric method `Credentials::initFromPlacementRequest` when application init form placement request +* add method `Services\Main\Service::getServerTime` returns current server time in the format YYYY-MM-DDThh:mm:ss±hh:mm. +* add method `Services\Main\Service::getCurrentUserProfile` return basic Information about the current user without any scopes +* add method `Services\Main\Service::getAccessName` returns access permission names. +* add method `Services\Main\Service::checkUserAccess` Checks if the current user has at least one permission of those specified by the + ACCESS parameter. +* add method `Services\Main\Service::getMethodAffordability` Method returns 2 parameters - isExisting and isAvailable +* add money type support by [phpmoney](https://github.com/moneyphp/money) +* add support fields `operating` and `operating_reset_at` at `Bitrix24\SDK\Core\Response\DTO\Time` datastructures + +### Changed + +* update scope list [расширить и актуализировать доступные скоупы](https://github.com/mesilov/bitrix24-php-sdk/issues/280) +* bump `symfony/*` to `6.*` version requirement. +* method `Services\Main\Service::getAvailableMethods` marks as deprecated +* method `Services\Main\Service::getAllMethods` marks as deprecated +* method `Services\Main\Service::getMethodsByScope` marks as deprecated +* ❗️fabric methods `Bitrix24\SDK\Core\Credentials` + renamed and now are [consistent](https://github.com/mesilov/bitrix24-php-sdk/issues/303): `createFromWebhook`, `createFromOAuth` + , `createFromPlacementRequest` +* ❗️deleted [unused class](https://github.com/mesilov/bitrix24-php-sdk/issues/303) `Bitrix24\SDK\Core\Response\DTO\ResponseDataCollection` +* ❗️deleted [redundant class](https://github.com/mesilov/bitrix24-php-sdk/issues/303) `Bitrix24\SDK\Core\Response\DTO\Result` +* ❗️deleted [method](https://github.com/mesilov/bitrix24-php-sdk/issues/303) `CoreBuilder::withWebhookUrl`, use + method `CoreBuilder::withCredentials` + +### Bugfix + +* add bugfix for batch method for reverse order queries +* fix type compatible errors for `Core\Result\AbstractItem` +* fix error in `NetworkTimingParser`, [error in NetworkTimingsErrorInfo](https://github.com/mesilov/bitrix24-php-sdk/issues/277) +* fix error in `RenewedAccessToken` DTO, remove `Scope` + enum [UnknownScopeCodeException - in refresh token response](https://github.com/mesilov/bitrix24-php-sdk/issues/295) + +### etc + +* add link to [boosty.to/bitrix24-php-sdk](https://boosty.to/bitrix24-php-sdk) for sponsoring development + +## 2.0-alpha.6 — 7.02.2022 ### Added diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..14eb68a4 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,39 @@ +# A quick guide to contribute to the project: + +## Installing the dev environment + +1. Fork the repo +2. Clone the repo to local +3. Install dependencies: `composer update` (this assumes you have 'composer' aliased to wherever your composer.phar lives) +4. Run the tests. We only take pull requests with passing tests, and it's great to know that you have a clean slate: + `composer phpstan-analyse` + `composer phpunit-run-unit-tests` + `composer phpunit-run-integration-tests` + +## Adding new features + +Pull requests with new features needs to be created against master branch. + +If new feature require BC Break please note that in your PR comment, it will added in next major version. +New features that does not have any BC Breaks are going to be added in next minor version. + +## Codding standards + +In order to fix codding standards please exeecute: + +```shell +composer phpstan-analyse +``` + +## Patches and bugfixes + +1. Check the oldest version that patch/bug fix can be applied. +2. Create PR against that version + + +## The actual contribution + +1. Make the changes/additions to the code, committing often and making clear what you've done +2. Make sure you write tests for your code, located in the folder structure +3. Run your tests (often and while coding) +4. Create Pull Request on github to against proper branch diff --git a/MIT-LICENSE.txt b/MIT-LICENSE.txt index deb1e09d..109e678b 100644 --- a/MIT-LICENSE.txt +++ b/MIT-LICENSE.txt @@ -1,5 +1,4 @@ -Copyright 2013 Mesilov Maxim -https://bitrixinsider.ru/ +Copyright 2022 Maxim Mesilov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/README.md b/README.md index 2656f480..97104ce4 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,10 @@ Performance improvements 🚀 - test coverage: unit, integration, contract - typical examples typical for different modes of operation and they are optimized for memory \ performance +### Sponsors + +Help bitrix24-php-sdk by [boosty.to/bitrix24-php-sdk](https://boosty.to/bitrix24-php-sdk) its development! + ### Architecture ### Abstraction layers @@ -121,7 +125,8 @@ Add `"mesilov/bitrix24-php-sdk": "2.x"` to `composer.json` of your application. ### Tests -Tests locate in folder `tests` and we have two test types +Tests locate in folder `tests` and we have two test types. +In folder tests create file `.env.local` and fill environment variables from `.env`. #### Unit tests @@ -184,7 +189,6 @@ See also the list of [contributors](https://github.com/mesilov/bitrix24-php-sdk/ email: -### Sponsors ### Documentation @@ -217,6 +221,10 @@ email: - покрытие тестами: unit, интеграционные, контрактные - есть типовые примеры характерные для разных режимов работы и они оптимизированы по памяти \ быстродействию +### Спонсоры + +Помогите развитию bitrix24-php-sdk подписавшись на [boosty.to/bitrix24-php-sdk](https://boosty.to/bitrix24-php-sdk)! + ### Ключевые особенности ### Слои SDK @@ -331,4 +339,53 @@ Symfony HttpClient JSON по HTTP/2 или HTTP/1.1 -## Спонсоры \ No newline at end of file +## Спонсоры + +### Тесты + +Тесты расположены в папке `tests` и бывают двух типов: юнит и интеграционные. +В папке `tests` создайте файл `.env.local` и заполните переменные из файла `.env`. + +#### Юнит тесты + +**Быстрые**, выполняются без сетевого взаимодействия с Битрикс 24. + +```shell +composer phpunit-run-unit-test +``` + +#### Интеграционные тесты + +**Медленные** тесты покрывают полный жизненный цикл CRUD операций подключение к Битрикс 24 происходи с помощью веб-хука. + +❗ Не запускайте интеграционные тесты на ваших production порталах они удалят все ваши данные ❗️ + +Для запуска интеграционных тестов вам нужно: + +1. Создать [Новый портал Битрикс 24](https://www.bitrix24.ru/create.php?p=255670) для запуска тестов. +2. Перейти в левое меню и нажать "Карта сайта". +3. Найти меню для "Разработчиков" +4. Кликнуть в меню «Другое» +5. Кликнуть в меню «Входящий веб-хук» +6. Выбрать все нужные расширения и нажать кнопку "сохранить". +7. Создать файл `/tests/.env.local` с переменными окружения которые скопировать из файла `/tests/.env` . + +```yaml +APP_ENV=dev +BITRIX24_WEBHOOK=https:// your portal webhook url +INTEGRATION_TEST_LOG_LEVEL=500 +``` + +8. Запуск из командной строки. + +```shell +composer composer phpunit-run-integration-tests +``` + +#### Статический анализ кодовой базы – phpstan + +Запуск из командной строки. + +```shell + composer phpstan-analyse +``` diff --git a/composer.json b/composer.json index 900ff842..7a54f0ad 100644 --- a/composer.json +++ b/composer.json @@ -19,23 +19,27 @@ "require": { "php": "7.4.*|8.*", "ext-json": "*", + "ext-bcmath": "*", "ext-curl": "*", "psr/log": "^1.1.4 || ^2.0 || ^3.0", "fig/http-message-util": "1.1.*", - "symfony/http-client": "5.4.*", - "symfony/http-client-contracts": "^2.5", - "symfony/event-dispatcher": "5.4.*", - "ramsey/uuid": "^4.2.3" + "symfony/http-client": "5.4.* || 6.*", + "symfony/http-client-contracts": "^2.5 || ^3.1", + "symfony/http-foundation": "5.4.* || 6.*", + "symfony/event-dispatcher": "5.4.* || 6.*", + "ramsey/uuid": "^4.2.3", + "moneyphp/money": "3.* || 4.*" }, "require-dev": { "monolog/monolog": "2.1.*", - "symfony/console": "5.4.*", - "symfony/dotenv": "5.4.*", - "symfony/debug-bundle": "5.4.*", - "phpstan/phpstan": "1.1.*", + "symfony/console": "5.4.* || 6.*", + "symfony/dotenv": "5.4.* || 6.*", + "symfony/debug-bundle": "5.4.* || 6.*", + "phpstan/phpstan": "1.*", "phpunit/phpunit": "9.5.*", - "symfony/stopwatch": "5.4.*", - "roave/security-advisories": "dev-master" + "symfony/stopwatch": "5.4.* || 6.*", + "roave/security-advisories": "dev-master", + "ext-intl": "*" }, "autoload": { "psr-4": { diff --git a/docs/RU/Application/new-local-application.md b/docs/RU/Application/new-local-application.md new file mode 100644 index 00000000..393a65a3 --- /dev/null +++ b/docs/RU/Application/new-local-application.md @@ -0,0 +1,23 @@ +# Создание Локального приложения +## Предусловия +1. Создайте 2 файла в корне рабочей папки например app: это `install.php` и `index.php`. +2. Содержимое файла `install.php`. + ```php + ``` +3. Для работы локального серверного приложения требуется рабочий веб сервер на машине разработчика. +4. Запускаем локальный веб-сервер, например так: +```shell +php -S 127.0.0.1:8080 +``` +3. Пробрасываем порт в большой интернет через сервис ngrok. +```shell +ngrok http 127.0.0.1:8080 +``` +4. После запуска ngrok будет выдан временный публичный адрес типо `https://7949-178-34-183-66.eu.ngrok.io`, который после выключения сервиса перестанет существовать. Этот адрес исчезнет после завершения ngrok. +5. Зарегистрируйте новый портал битрикс 24. +6. Включите тестовый период для маркет плейса и тарифного плана. +7. Открой портал и перейдите в меню. + 1. Откройте левое меню, выберите "Разработчикам" + 2. Выберите "Другое" + 3. Откройте "Локальное приложение" + 4. Зарегистрируйте новое локальное приложение с нужным вам скоупом. diff --git a/docs/RU/Core/Auth/auth.md b/docs/RU/Core/Auth/auth.md index 2e0364f5..eaf66877 100644 --- a/docs/RU/Core/Auth/auth.md +++ b/docs/RU/Core/Auth/auth.md @@ -37,7 +37,7 @@ $result = json_decode($result->getContent(), true); var_dump($result); ``` -## подключение к Битрикс24 с использованием OAuth 2.0 +## подключение к Битрикс24 с использованием OAuth 2.0 ```php core->call( + 'telephony.externalLine.add', + [ + 'NUMBER' => $lineNumber, + 'NAME' => $nameLine, + ] + )); + } + ``` + 3. В папке Result будут размещены результаты наших методов(то что они будут возвращать). + 1. Для примера создадим ExternalLineAddResult.php + ```php + getCoreResponse()->getResponseData()->getResult()->getResultData()['ID']; + } + + } + 4. Также в папке `src/Services/(название вашего сервиса)` размещаем (название вашего сервиса)ServiceBuilder.php. Этот сервис нужен для подключения нашего скоупа с тестами. +6. После того как мы добавили наши методы для работы с Телефонией нужно их затестить. Создадим в папке `tests/Integration/Services/Telephony/Service/` наши тесты и проверим все ли работает как надо ExternalLineTest.php. + ```php + externalLineService->add((string)time(), sprintf('phpUnit-%s', time()))->getId()); + } + /** + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public function setUp(): void + { + $this->externalLineService = Fabric::getServiceBuilder()->getTelephonyScope()->externalline(); + } + } + ``` \ No newline at end of file diff --git a/examples/core/batch-query-iterable-read-examp.php b/examples/core/batch-query-iterable-read-examp.php deleted file mode 100644 index 147a4b0b..00000000 --- a/examples/core/batch-query-iterable-read-examp.php +++ /dev/null @@ -1,73 +0,0 @@ -pushHandler(new StreamHandler('examples/logs/b24-api-client.log', Logger::DEBUG)); -$log->pushProcessor(new \Monolog\Processor\MemoryUsageProcessor(true, true)); -$log->pushProcessor(new \Monolog\Processor\IntrospectionProcessor()); -$log->debug('=============================================================='); - -try { - print('получаем данные:' . PHP_EOL); - - $core = (new \Bitrix24\SDK\Core\CoreBuilder()) - ->withLogger($log) - // INSERT YOUR WEBHOOK HERE - ->withWebhookUrl('https://') - // INSERT YOUR WEBHOOK HERE - ->build(); - $dealsService = new \Bitrix24\SDK\Services\CRM\Deals\Service\Deals($core, $log); - - $select = ['ID', 'TITLE']; - $firstResult = $dealsService->list([], ['>ID' => 50], $select); - $totalCount = $firstResult->getResponseData()->getPagination()->getTotal(); - - - // примеры формирования батч-запросов на чтение - // задача: прочитать все сделки из Б24 - // простая стратегия (с подсчётом количества элементов на стороне Б24 на каждом шаге): - - - $order = ['ID' => 'ASC']; - $filter = ['>ID' => 1]; - $select = ['ID', 'NAME', 'PHONE', 'EMAIL', 'IM']; - - $timeStart = microtime(true); - $elementsFromBatchCount = 0; - $batch = new \Bitrix24\SDK\Core\Batch($core, $log); - foreach ($batch->getTraversableList('crm.contact.list', $order, $filter, $select, 6000) as $queryItem) { - $curTime = microtime(true); - $elementsFromBatchCount++; - print(sprintf( - '%s Mb| %s sec |item %s |%s - %s ', - round(memory_get_peak_usage(true) / 1024 / 1024, 2), - round($curTime - $timeStart, 2), - $elementsFromBatchCount, - $queryItem['ID'], - $queryItem['NAME'] - ) . PHP_EOL); - } - - $timeEnd = microtime(true); - print(sprintf('batch query duration: %s seconds', round($timeEnd - $timeStart, 2)) . PHP_EOL . PHP_EOL); - print(sprintf('elements in bitrix24 count: %s', $totalCount) . PHP_EOL); - print(sprintf('elements from batch count: %s ', $elementsFromBatchCount) . PHP_EOL . PHP_EOL); -} catch (\Throwable $exception) { - print(sprintf('ошибка: %s', $exception->getMessage()) . PHP_EOL); - print(sprintf('тип: %s', get_class($exception)) . PHP_EOL); - print(sprintf('trace: %s', $exception->getTraceAsString()) . PHP_EOL); -} - - - - - - - - - diff --git a/examples/core/batch-query-iterable-write-examp.php b/examples/core/batch-query-iterable-write-examp.php deleted file mode 100644 index 8ffdbd20..00000000 --- a/examples/core/batch-query-iterable-write-examp.php +++ /dev/null @@ -1,81 +0,0 @@ -pushHandler(new StreamHandler('examples/logs/b24-api-client.log', Logger::DEBUG)); -$log->pushProcessor(new \Monolog\Processor\MemoryUsageProcessor(true, true)); - -try { - $core = (new \Bitrix24\SDK\Core\CoreBuilder()) - ->withLogger($log) - // INSERT YOUR WEBHOOK HERE - ->withWebhookUrl('https://') - // INSERT YOUR WEBHOOK HERE - ->build(); - - $arraySize = 100; - print(sprintf('Prepare raw data example...') . PHP_EOL); - $rawDeals = []; - for ($i = 0; $i < $arraySize; $i++) { - $rawDeals[] = [ - 'TITLE' => sprintf('deal-%s', $i), - 'OPPORTUNITY' => 500, - 'CONTACT_ID' => 76, - ]; - } - print(sprintf('deals data count: %s', count($rawDeals)) . PHP_EOL); - print(sprintf('--------') . PHP_EOL); - - - // собираем операции добавления сделок в батч-запросы - $batch = new \Bitrix24\SDK\Core\Batch($core, $log); - foreach ($rawDeals as $cnt => $deal) { - $batch->addCommand('crm.deal.add', $deal); - } - print(sprintf('batch commands registered') . PHP_EOL); - - - // получаем данные батч-запросов - print(sprintf('call batch queries and get traversable results for each command...') . PHP_EOL); - - - // iterate api-calls result - $timeStart = microtime(true); - foreach ($batch->getTraversable(true) as $queryCnt => $queryResultData) { - /** - * @var $queryResultData \Bitrix24\SDK\Core\Response\DTO\ResponseData - */ - - print(sprintf(' single query number %s: ', $queryCnt) . PHP_EOL); - print(sprintf( - ' time |start: %s |duration %s |', - $queryResultData->getTime()->getDateStart()->format('H:i:s'), - $queryResultData->getTime()->getDuration(), - ) . PHP_EOL); - - print(sprintf(' deal id: %s', $queryResultData->getResult()->getResultData()[0]) . PHP_EOL); - - print(sprintf(' --') . PHP_EOL); - } - $timeEnd = microtime(true); - print(sprintf('batch query duration: %s seconds', round($timeEnd - $timeStart, 2)) . PHP_EOL . PHP_EOL); -} catch (\Throwable $exception) { - print(sprintf('ошибка: %s', $exception->getMessage()) . PHP_EOL); - print(sprintf('тип: %s', get_class($exception)) . PHP_EOL); - print(sprintf('trace: %s', $exception->getTraceAsString()) . PHP_EOL); -} - - - - - - - - - - diff --git a/examples/core/composer.json b/examples/core/composer.json deleted file mode 100644 index ceb68f23..00000000 --- a/examples/core/composer.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "require": { - "monolog/monolog": "2.*" - }, - "require-dev": { - "roave/security-advisories": "dev-master" - } -} \ No newline at end of file diff --git a/examples/core/core-examp.php b/examples/core/core-examp.php deleted file mode 100644 index e4d01a0e..00000000 --- a/examples/core/core-examp.php +++ /dev/null @@ -1,26 +0,0 @@ -pushHandler(new StreamHandler('b24-api-client-debug.log', Logger::DEBUG)); - -$client = HttpClient::create(); - -$credentials = new \Bitrix24\SDK\Core\Credentials\Credentials( - new \Bitrix24\SDK\Core\Credentials\WebhookUrl('b24 domain'), - null, - null -); - -$apiClient = new \Bitrix24\SDK\Core\ApiClient($credentials, $client, $log); - -$result = $apiClient->getResponse('crm.deal.get', ['id' => 5]); - -var_dump($result->getContent()); diff --git a/examples/core/oauth-examp.php b/examples/core/oauth-examp.php deleted file mode 100644 index 1e9badd6..00000000 --- a/examples/core/oauth-examp.php +++ /dev/null @@ -1,61 +0,0 @@ -pushHandler(new StreamHandler('b24-api-client-debug.log', Logger::DEBUG)); - -$client = HttpClient::create(['http_version' => '2.0']); -$traceableClient = new \Symfony\Component\HttpClient\TraceableHttpClient($client); -$traceableClient->setLogger($log); - -$appProfile = new \Bitrix24\SDK\Core\Credentials\ApplicationProfile( - 'local.5f9d4c50b2bf08.70341243', - 'YE56q7neK8SJgP8xqDBlTP2oPYSUf7HUySkob0w9wOWFr1XZCv', - new \Bitrix24\SDK\Core\Credentials\Scope( - [ - 'crm', - ] - ) -); -$token = new \Bitrix24\SDK\Core\Credentials\AccessToken( - '50cc… access token', - '404b… refresh token', - 0 -); -$domain = 'https://domain.bitrix24.ru'; -$credentials = \Bitrix24\SDK\Core\Credentials\Credentials::createForOAuth($token, $appProfile, $domain); - -try { - $apiClient = new \Bitrix24\SDK\Core\ApiClient($credentials, $traceableClient, $log); - - $ed = new \Symfony\Component\EventDispatcher\EventDispatcher(); - $ed->addListener( - \Bitrix24\SDK\Events\AuthTokenRenewedEvent::class, - static function (\Bitrix24\SDK\Events\AuthTokenRenewedEvent $event) { - var_dump('AuthTokenRenewed!'); - print($event->getRenewedToken()->getAccessToken()->getAccessToken() . PHP_EOL); - } - ); - - $app = (new \Bitrix24\SDK\Core\CoreBuilder())->withCredentials($credentials)->withApiClient($apiClient)->build(); - - $log->debug('================================'); - - // api call with expired access token - $res = $app->call('app.info'); - print('result:' . PHP_EOL); - - var_dump($res->getResponseData()->getResult()->getResultData()); - var_dump($res->getResponseData()->getTime()->getDuration()); -} catch (\Throwable $exception) { - print(sprintf('error: %s', $exception->getMessage()) . PHP_EOL); - print(sprintf('class: %s', get_class($exception)) . PHP_EOL); - print(sprintf('trace: %s', $exception->getTraceAsString()) . PHP_EOL); -} \ No newline at end of file diff --git a/examples/services/service-examp.php b/examples/services/service-examp.php deleted file mode 100644 index f048618b..00000000 --- a/examples/services/service-examp.php +++ /dev/null @@ -1,41 +0,0 @@ -pushHandler(new StreamHandler('examples/logs/b24-api-client.log', Logger::DEBUG)); -$log->pushProcessor(new \Monolog\Processor\MemoryUsageProcessor(true, true)); -$log->pushProcessor(new \Monolog\Processor\IntrospectionProcessor()); -$log->debug('=============================================================='); - -try { - print('получаем данные:' . PHP_EOL); - - // сконфигурировали SDK - $core = (new \Bitrix24\SDK\Core\CoreBuilder()) - ->withLogger($log) - // INSERT YOUR WEBHOOK HERE - ->withWebhookUrl('') - // INSERT YOUR WEBHOOK HERE - ->build(); - $batch = new \Bitrix24\SDK\Core\Batch($core, $log); - $serviceBuilder = new ServiceBuilder($core, $batch, $log); - - // получили сервис по работе с контактами из модуля CRM - // именно сервис предоставляет CRUD+ api по работе с сущностью - $contactService = $serviceBuilder->getCRMScope()->contacts(); - - // получили первые 50 контактов вызвав метод crm.contact.list - $contacts = $contactService->list([], [], [], 0); - var_dump($contacts->getResponseData()->getResult()->getResultData()); - var_dump($contacts->getResponseData()->getPagination()->getTotal()); -} catch (\Throwable $exception) { - print(sprintf('ошибка: %s', $exception->getMessage()) . PHP_EOL); - print(sprintf('тип: %s', get_class($exception)) . PHP_EOL); - print(sprintf('trace: %s', $exception->getTraceAsString()) . PHP_EOL); -} \ No newline at end of file diff --git a/src/Application/ApplicationStatus.php b/src/Application/ApplicationStatus.php new file mode 100644 index 00000000..54500ccf --- /dev/null +++ b/src/Application/ApplicationStatus.php @@ -0,0 +1,119 @@ +statusCode = 'free'; + break; + case self::STATUS_SHORT_DEMO: + $this->statusCode = 'demo'; + break; + case self::STATUS_SHORT_TRIAL: + $this->statusCode = 'trial'; + break; + case self::STATUS_SHORT_PAID: + $this->statusCode = 'paid'; + break; + case self::STATUS_SHORT_LOCAL: + $this->statusCode = 'local'; + break; + case self::STATUS_SHORT_SUBSCRIPTION: + $this->statusCode = 'subscription'; + break; + default: + throw new InvalidArgumentException( + sprintf('unknown application status code %s', $statusShortCode) + ); + } + } + + /** + * @return bool + */ + public function isFree(): bool + { + return 'free' === $this->statusCode; + } + + /** + * @return bool + */ + public function isDemo(): bool + { + return 'demo' === $this->statusCode; + } + + /** + * @return bool + */ + public function isTrial(): bool + { + return 'trial' === $this->statusCode; + } + + /** + * @return bool + */ + public function isPaid(): bool + { + return 'paid' === $this->statusCode; + } + + /** + * @return bool + */ + public function isLocal(): bool + { + return 'local' === $this->statusCode; + } + + /** + * @return bool + */ + public function isSubscription(): bool + { + return 'subscription' === $this->statusCode; + } + + /** + * @return string + */ + public function getStatusCode(): string + { + return $this->statusCode; + } + + /** + * @param \Symfony\Component\HttpFoundation\Request $request + * + * @return self + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public static function initFromRequest(Request $request): self + { + return new self($request->request->getAlpha('status')); + } +} \ No newline at end of file diff --git a/src/Application/Requests/AbstractRequest.php b/src/Application/Requests/AbstractRequest.php new file mode 100644 index 00000000..be080268 --- /dev/null +++ b/src/Application/Requests/AbstractRequest.php @@ -0,0 +1,28 @@ +request = $request; + } + + /** + * @return \Symfony\Component\HttpFoundation\Request + */ + public function getRequest(): Request + { + return $this->request; + } +} \ No newline at end of file diff --git a/src/Application/Requests/Events/AbstractEventRequest.php b/src/Application/Requests/Events/AbstractEventRequest.php new file mode 100644 index 00000000..ca344c96 --- /dev/null +++ b/src/Application/Requests/Events/AbstractEventRequest.php @@ -0,0 +1,53 @@ +getContent(), $payload); + $this->eventPayload = $payload; + + $this->eventCode = $this->eventPayload['event']; + $this->timestamp = (int)$this->eventPayload['ts']; + } + + /** + * @return int + */ + public function getTimestamp(): int + { + return $this->timestamp; + } + + /** + * @return string + */ + public function getEventCode(): string + { + return $this->eventCode; + } + + /** + * @return array + */ + public function getEventPayload(): array + { + return $this->eventPayload; + } +} \ No newline at end of file diff --git a/src/Application/Requests/Events/OnApplicationInstall/ApplicationData.php b/src/Application/Requests/Events/OnApplicationInstall/ApplicationData.php new file mode 100644 index 00000000..a63186a0 --- /dev/null +++ b/src/Application/Requests/Events/OnApplicationInstall/ApplicationData.php @@ -0,0 +1,17 @@ +eventPayload['data']); + } + + /** + * @return \Bitrix24\SDK\Application\Requests\Events\OnApplicationInstall\Auth + */ + public function getAuth(): Auth + { + return new Auth($this->eventPayload['auth']); + } +} \ No newline at end of file diff --git a/src/Application/Requests/Events/OnApplicationUninstall/ApplicationData.php b/src/Application/Requests/Events/OnApplicationUninstall/ApplicationData.php new file mode 100644 index 00000000..bc49fb2e --- /dev/null +++ b/src/Application/Requests/Events/OnApplicationUninstall/ApplicationData.php @@ -0,0 +1,15 @@ +eventPayload['data']); + } + + /** + * @return \Bitrix24\SDK\Application\Requests\Events\OnApplicationUninstall\Auth + */ + public function getAuth(): Auth + { + return new Auth($this->eventPayload['auth']); + } +} \ No newline at end of file diff --git a/src/Application/Requests/Placement/PlacementRequest.php b/src/Application/Requests/Placement/PlacementRequest.php new file mode 100644 index 00000000..99e3fb7c --- /dev/null +++ b/src/Application/Requests/Placement/PlacementRequest.php @@ -0,0 +1,109 @@ + + */ + private array $placementOptions; + private string $domainUrl; + private string $languageCode; + + /** + * @param \Symfony\Component\HttpFoundation\Request $request + * + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws \JsonException + */ + public function __construct(Request $request) + { + parent::__construct($request); + $query = parse_url($request->getRequestUri())['query']; + $queryArgs = []; + parse_str($query, $queryArgs); + $this->domainUrl = sprintf('https://%s', $queryArgs['DOMAIN']); + $this->languageCode = $queryArgs['LANG']; + + $this->accessToken = AccessToken::initFromPlacementRequest($request); + $this->applicationStatus = ApplicationStatus::initFromRequest($request); + $this->memberId = $request->request->get('member_id'); + $this->code = (string)$request->request->get('PLACEMENT'); + + $options = json_decode((string)$request->request->get('PLACEMENT_OPTIONS'), true, 512, JSON_THROW_ON_ERROR); + if ($options === null) { + throw new InvalidArgumentException('invalid data in PLACEMENT_OPTIONS json payload'); + } + // fix "undefined" string in options when placement loaded in telephony settings + if (!is_array($options)) { + $options = []; + } + $this->placementOptions = $options; + } + + public function getApplicationStatus(): ApplicationStatus + { + return $this->applicationStatus; + } + + /** + * @return string + */ + public function getMemberId(): string + { + return $this->memberId; + } + + /** + * @return \Bitrix24\SDK\Core\Credentials\AccessToken + */ + public function getAccessToken(): AccessToken + { + return $this->accessToken; + } + + /** + * @return string + */ + public function getCode(): string + { + return $this->code; + } + + /** + * @return array|mixed + */ + public function getPlacementOptions() + { + return $this->placementOptions; + } + + /** + * @return mixed|string + */ + public function getDomainUrl() + { + return $this->domainUrl; + } + + /** + * @return mixed|string + */ + public function getLanguageCode() + { + return $this->languageCode; + } +} \ No newline at end of file diff --git a/src/Core/ApiClient.php b/src/Core/ApiClient.php index b637a71c..46ab0497 100644 --- a/src/Core/ApiClient.php +++ b/src/Core/ApiClient.php @@ -143,8 +143,10 @@ public function getResponse(string $apiMethod, array $parameters = []): Response } $requestOptions = [ - 'json' => $parameters, - 'headers' => $this->getDefaultHeaders(), + 'json' => $parameters, + 'headers' => $this->getDefaultHeaders(), + // disable redirects, try to catch portal change domain name event + 'max_redirects' => 0, ]; $response = $this->client->request($method, $url, $requestOptions); diff --git a/src/Core/Batch.php b/src/Core/Batch.php index 03379d3a..10224162 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -164,6 +164,83 @@ public function deleteEntityItems(string $apiMethod, array $entityItemId): Gener $this->logger->debug('deleteEntityItems.finish'); } + /** + * Update entity items with batch call + * + * Update elements in array with structure + * element_id => [ + * 'fields' => [], // required element fields to update + * 'params' => [] // optional fields + * ] + * + * @param string $apiMethod + * @param array> $entityItems + * + * @return Generator|ResponseData[] + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function updateEntityItems(string $apiMethod, array $entityItems): Generator + { + $this->logger->debug( + 'updateEntityItems.start', + [ + 'apiMethod' => $apiMethod, + 'entityItems' => $entityItems, + ] + ); + + try { + $this->clearCommands(); + foreach ($entityItems as $entityItemId => $entityItem) { + if (!is_int($entityItemId)) { + throw new InvalidArgumentException( + sprintf( + 'invalid type «%s» of entity id «%s», entity id must be integer type', + gettype($entityItemId), + $entityItemId + ) + ); + } + if (!array_key_exists('fields', $entityItem)) { + throw new InvalidArgumentException( + sprintf('array key «fields» not found in entity item with id %s', $entityItemId) + ); + } + + $this->registerCommand($apiMethod, [ + 'id' => $entityItemId, + 'fields' => $entityItem['fields'], + 'params' => $entityItem['params'], + ]); + } + + foreach ($this->getTraversable(true) as $cnt => $updatedItemResult) { + yield $cnt => $updatedItemResult; + } + } catch (InvalidArgumentException $exception) { + $errorMessage = sprintf('batch update entity items: %s', $exception->getMessage()); + $this->logger->error( + $errorMessage, + [ + 'trace' => $exception->getTrace(), + ] + ); + throw $exception; + } catch (\Throwable $exception) { + $errorMessage = sprintf('batch update entity items: %s', $exception->getMessage()); + $this->logger->error( + $errorMessage, + [ + 'trace' => $exception->getTrace(), + ] + ); + + throw new BaseException($errorMessage, $exception->getCode(), $exception); + } + + $this->logger->debug('updateEntityItems.finish'); + } + /** * Register api command to command collection for batch calls * @@ -261,14 +338,15 @@ public function getTraversableList( array $select, ?int $limit = null ): Generator { - $this->logger->debug('getTraversableList.start', - [ - 'apiMethod' => $apiMethod, - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'limit' => $limit, - ] + $this->logger->debug( + 'getTraversableList.start', + [ + 'apiMethod' => $apiMethod, + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'limit' => $limit, + ] ); // strategy.3 — ID filter, batch, no count, order @@ -298,7 +376,6 @@ public function getTraversableList( // todo проверили, что если есть limit, то он >1 // todo проверили, что в фильтре нет поля ID, т.к. мы с ним будем работать - $firstResultPage = $this->core->call( $apiMethod, [ @@ -309,10 +386,13 @@ public function getTraversableList( ] ); $totalElementsCount = $firstResultPage->getResponseData()->getPagination()->getTotal(); + $this->logger->debug('getTraversableList.totalElementsCount', [ + 'totalElementsCount' => $totalElementsCount, + ]); // filtered elements count less than or equal one result page(50 elements) $elementsCounter = 0; if ($totalElementsCount <= self::MAX_ELEMENTS_IN_PAGE) { - foreach ($firstResultPage->getResponseData()->getResult()->getResultData() as $cnt => $listElement) { + foreach ($firstResultPage->getResponseData()->getResult() as $cnt => $listElement) { $elementsCounter++; if ($limit !== null && $elementsCounter > $limit) { return; @@ -327,9 +407,9 @@ public function getTraversableList( // filtered elements count more than one result page(50 elements) // return first page $lastElementIdInFirstPage = null; - foreach ($firstResultPage->getResponseData()->getResult()->getResultData() as $cnt => $listElement) { + foreach ($firstResultPage->getResponseData()->getResult() as $cnt => $listElement) { $elementsCounter++; - $lastElementIdInFirstPage = $listElement['ID']; + $lastElementIdInFirstPage = (int)$listElement['ID']; if ($limit !== null && $elementsCounter > $limit) { return; } @@ -351,8 +431,17 @@ public function getTraversableList( 'start' => 0, ] ); - - $lastElementId = (int)$lastResultPage->getResponseData()->getResult()->getResultData()[0]['ID']; + $lastElementId = (int)$lastResultPage->getResponseData()->getResult()[0]['ID']; + // reverse order if you need + if ($lastElementIdInFirstPage > $lastElementId) { + $tmp = $lastElementIdInFirstPage; + $lastElementIdInFirstPage = $lastElementId; + $lastElementId = $tmp; + } + $this->logger->debug('getTraversableList.lastElementsId', [ + 'lastElementIdInFirstPage' => $lastElementIdInFirstPage, + 'lastElementId' => $lastElementId, + ]); // register commands with updated filter //more than one page in results - register list commands @@ -408,7 +497,7 @@ public function getTraversableList( ] ); // iterate items in batch query result - foreach ($queryResultData->getResult()->getResultData() as $cnt => $listElement) { + foreach ($queryResultData->getResult() as $cnt => $listElement) { $elementsCounter++; if ($limit !== null && $elementsCounter > $limit) { return; @@ -563,7 +652,7 @@ public function getTraversableListWithCount( ] ); // iterate items in batch query result - foreach ($queryResultData->getResult()->getResultData() as $cnt => $listElement) { + foreach ($queryResultData->getResult() as $cnt => $listElement) { $elementsCounter++; if ($limit !== null && $elementsCounter > $limit) { return; @@ -613,13 +702,13 @@ protected function getTraversable(bool $isHaltOnError): Generator // single queries // todo handle error field - $resultDataItems = $response->getResult()->getResultData()['result']; - $resultQueryTimeItems = $response->getResult()->getResultData()['result_time']; + $resultDataItems = $response->getResult()['result']; + $resultQueryTimeItems = $response->getResult()['result_time']; // list queries //todo handle result_error for list queries - $resultNextItems = $response->getResult()->getResultData()['result_next']; - $totalItems = $response->getResult()->getResultData()['result_total']; + $resultNextItems = $response->getResult()['result_next']; + $totalItems = $response->getResult()['result_total']; foreach ($resultDataItems as $singleQueryKey => $singleQueryResult) { if (!is_array($singleQueryResult)) { $singleQueryResult = [$singleQueryResult]; @@ -639,7 +728,7 @@ protected function getTraversable(bool $isHaltOnError): Generator } yield new ResponseData( - new Result($singleQueryResult), + $singleQueryResult, Time::initFromResponse($resultQueryTimeItems[$singleQueryKey]), new Pagination($nextItem, $total) ); diff --git a/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php b/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php index a2d1ce9e..e1d6c8c8 100644 --- a/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php +++ b/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php @@ -119,7 +119,7 @@ public function getTraversableList(string $apiMethod, array $order, array $filte ); - foreach ($resultPage->getResponseData()->getResult()->getResultData() as $cnt => $item) { + foreach ($resultPage->getResponseData()->getResult() as $cnt => $item) { $currentElementId = (int)$item['ID']; @@ -167,7 +167,7 @@ private function getFirstElementId(string $apiMethod, array $filter, array $sele ] ); - $elementId = $firstResultPage->getResponseData()->getResult()->getResultData()[0]['ID']; + $elementId = $firstResultPage->getResponseData()->getResult()[0]['ID']; $this->log->debug('FilterWithoutBatchWithoutCountOrder.getFirstElementId.finish', [ 'elementId' => $elementId, @@ -206,7 +206,7 @@ private function getLastElementId(string $apiMethod, array $filter, array $selec ] ); - $elementId = $lastResultPage->getResponseData()->getResult()->getResultData()[0]['ID']; + $elementId = $lastResultPage->getResponseData()->getResult()[0]['ID']; $this->log->debug('FilterWithoutBatchWithoutCountOrder.getLastElementId.finish', [ 'elementId' => $elementId, diff --git a/src/Core/Contracts/BatchInterface.php b/src/Core/Contracts/BatchInterface.php index d259a9d2..b6f0744e 100644 --- a/src/Core/Contracts/BatchInterface.php +++ b/src/Core/Contracts/BatchInterface.php @@ -18,11 +18,11 @@ interface BatchInterface /** * Batch wrapper for *.list methods without counting elements on every api-call * - * @param string $apiMethod - * @param array $order - * @param array $filter - * @param array $select - * @param int|null $limit + * @param string $apiMethod + * @param array $order + * @param array $filter + * @param array $select + * @param int|null $limit * * @return Generator * @throws BaseException @@ -79,5 +79,14 @@ public function addEntityItems(string $apiMethod, array $entityItems): Generator */ public function deleteEntityItems(string $apiMethod, array $entityItemId): Generator; - //todo add updateEntityItems + /** + * Update entity items with batch call + * + * @param string $apiMethod + * @param array $entityItems + * + * @return Generator|ResponseData[] + * @throws BaseException + */ + public function updateEntityItems(string $apiMethod, array $entityItems): Generator; } \ No newline at end of file diff --git a/src/Core/Contracts/UpdatedItemResultInterface.php b/src/Core/Contracts/UpdatedItemResultInterface.php new file mode 100644 index 00000000..a1dda726 --- /dev/null +++ b/src/Core/Contracts/UpdatedItemResultInterface.php @@ -0,0 +1,15 @@ +logger); break; + case StatusCodeInterface::STATUS_FOUND: + // change domain url + $portalOldDomainUrlHost = $this->apiClient->getCredentials()->getDomainUrl(); + $newDomain = parse_url($apiCallResponse->getHeaders(false)['location'][0]); + $portalNewDomainUrlHost = sprintf('%s://%s', $newDomain['scheme'], $newDomain['host']); + $this->apiClient->getCredentials()->setDomainUrl($portalNewDomainUrlHost); + $this->logger->debug('domain url changed', [ + 'oldDomainUrl' => $portalOldDomainUrlHost, + 'newDomainUrl' => $portalNewDomainUrlHost, + ]); + + // repeat api-call to new domain url + $response = $this->call($apiMethod, $parameters); + $this->logger->debug( + 'api call repeated to new domain url', + [ + 'domainUrl' => $portalNewDomainUrlHost, + 'repeatedApiMethod' => $apiMethod, + 'httpStatusCode' => $response->getHttpResponse()->getStatusCode(), + ] + ); + // dispatch event, application listeners update domain url host in accounts repository + $this->eventDispatcher->dispatch(new PortalDomainUrlChangedEvent($portalOldDomainUrlHost, $portalNewDomainUrlHost)); + break; case StatusCodeInterface::STATUS_UNAUTHORIZED: $body = $apiCallResponse->toArray(false); - $this->logger->notice( + $this->logger->debug( 'UNAUTHORIZED request', [ 'body' => $body, diff --git a/src/Core/CoreBuilder.php b/src/Core/CoreBuilder.php index d55e4109..e188ae62 100644 --- a/src/Core/CoreBuilder.php +++ b/src/Core/CoreBuilder.php @@ -27,7 +27,6 @@ class CoreBuilder protected HttpClientInterface $httpClient; protected EventDispatcherInterface $eventDispatcher; protected LoggerInterface $logger; - protected ?WebhookUrl $webhookUrl; protected ?Credentials $credentials; protected ApiLevelErrorHandler $apiLevelErrorHandler; @@ -44,7 +43,6 @@ public function __construct() 'timeout' => 120, ] ); - $this->webhookUrl = null; $this->credentials = null; $this->apiClient = null; $this->apiLevelErrorHandler = new ApiLevelErrorHandler($this->logger); @@ -58,17 +56,6 @@ public function __construct() public function withCredentials(Credentials $credentials): self { $this->credentials = $credentials; - return $this; - } - - /** - * @param string $webhookUrl - * - * @return $this - */ - public function withWebhookUrl(string $webhookUrl): self - { - $this->webhookUrl = new WebhookUrl($webhookUrl); return $this; } @@ -115,10 +102,8 @@ public function withEventDispatcher(EventDispatcherInterface $eventDispatcher): */ public function build(): CoreInterface { - if ($this->webhookUrl !== null) { - $this->credentials = Credentials::createForWebHook($this->webhookUrl); - } elseif ($this->credentials === null) { - throw new InvalidArgumentException('you must set webhook url or oauth credentials'); + if ($this->credentials === null) { + throw new InvalidArgumentException('you must set credentials before call method build'); } if ($this->apiClient === null) { diff --git a/src/Core/Credentials/AccessToken.php b/src/Core/Credentials/AccessToken.php index 794d13a3..8cefe7d4 100644 --- a/src/Core/Credentials/AccessToken.php +++ b/src/Core/Credentials/AccessToken.php @@ -4,6 +4,9 @@ namespace Bitrix24\SDK\Core\Credentials; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Symfony\Component\HttpFoundation\Request; + /** * Class AccessToken * @@ -74,4 +77,27 @@ public static function initFromArray(array $request): self (int)$request['expires'] ); } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public static function initFromPlacementRequest(Request $request): self + { + $requestFields = $request->request->all(); + if (!array_key_exists('AUTH_ID', $requestFields)) { + throw new InvalidArgumentException('field AUTH_ID not fount in request'); + } + if (!array_key_exists('REFRESH_ID', $requestFields)) { + throw new InvalidArgumentException('field REFRESH_ID not fount in request'); + } + if (!array_key_exists('AUTH_EXPIRES', $requestFields)) { + throw new InvalidArgumentException('field AUTH_EXPIRES not fount in request'); + } + + return new self( + (string)$request->request->get('AUTH_ID'), + (string)$request->request->get('REFRESH_ID'), + $request->request->getInt('AUTH_EXPIRES'), + ); + } } \ No newline at end of file diff --git a/src/Core/Credentials/ApplicationProfile.php b/src/Core/Credentials/ApplicationProfile.php index ea5f1f6e..9b8816da 100644 --- a/src/Core/Credentials/ApplicationProfile.php +++ b/src/Core/Credentials/ApplicationProfile.php @@ -4,6 +4,8 @@ namespace Bitrix24\SDK\Core\Credentials; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; + /** * Class ApplicationProfile * @@ -11,18 +13,12 @@ */ class ApplicationProfile { - /** - * @var string - */ - private $clientId; - /** - * @var string - */ - private $clientSecret; - /** - * @var Scope - */ - private $scope; + private const BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID = 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID'; + private const BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET = 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET'; + private const BITRIX24_PHP_SDK_APPLICATION_SCOPE = 'BITRIX24_PHP_SDK_APPLICATION_SCOPE'; + private string $clientId; + private string $clientSecret; + private Scope $scope; /** * ApplicationProfile constructor. @@ -61,4 +57,26 @@ public function getScope(): Scope { return $this->scope; } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public static function initFromArray(array $appProfile): self + { + if (!array_key_exists(self::BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID, $appProfile)) { + throw new InvalidArgumentException(sprintf('in array key %s not found', self::BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID)); + } + if (!array_key_exists(self::BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET, $appProfile)) { + throw new InvalidArgumentException(sprintf('in array key %s not found', self::BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET)); + } + if (!array_key_exists(self::BITRIX24_PHP_SDK_APPLICATION_SCOPE, $appProfile)) { + throw new InvalidArgumentException(sprintf('in array key %s not found', self::BITRIX24_PHP_SDK_APPLICATION_SCOPE)); + } + + return new self( + $appProfile[self::BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID], + $appProfile[self::BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET], + new Scope(str_replace(' ', '', explode(',', $appProfile[self::BITRIX24_PHP_SDK_APPLICATION_SCOPE]))), + ); + } } \ No newline at end of file diff --git a/src/Core/Credentials/Credentials.php b/src/Core/Credentials/Credentials.php index 8c8932d2..54260ac6 100644 --- a/src/Core/Credentials/Credentials.php +++ b/src/Core/Credentials/Credentials.php @@ -4,6 +4,9 @@ namespace Bitrix24\SDK\Core\Credentials; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Application\Requests\Placement\PlacementRequest; + /** * Class Credentials * @@ -23,6 +26,8 @@ class Credentials * @param AccessToken|null $accessToken * @param ApplicationProfile|null $applicationProfile * @param string|null $domainUrl + * + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException */ public function __construct( ?WebhookUrl $webhookUrl, @@ -33,7 +38,11 @@ public function __construct( $this->webhookUrl = $webhookUrl; $this->accessToken = $accessToken; $this->applicationProfile = $applicationProfile; - $this->domainUrl = $domainUrl; + + if ($domainUrl !== null) { + $this->setDomainUrl($domainUrl); + } + if ($this->accessToken === null && $this->webhookUrl === null) { throw new \LogicException('you must set on of auth type: webhook or OAuth 2.0'); } @@ -50,6 +59,27 @@ public function setAccessToken(AccessToken $accessToken): void $this->accessToken = $accessToken; } + /** + * Set domain url + * + * @param string $domainUrl + * + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public function setDomainUrl(string $domainUrl): void + { + $parseResult = parse_url($domainUrl); + if (!array_key_exists('scheme', $parseResult)) { + $domainUrl = 'https://' . $domainUrl; + } + + if (filter_var($domainUrl, FILTER_VALIDATE_URL) === false) { + throw new InvalidArgumentException(sprintf('domain URL %s is invalid', $domainUrl)); + } + $this->domainUrl = $domainUrl; + } + /** * @return ApplicationProfile|null */ @@ -65,13 +95,11 @@ public function getDomainUrl(): string { if ($this->getWebhookUrl() !== null) { $arUrl = parse_url($this->getWebhookUrl()->getUrl()); - - $url = sprintf('%s://%s', $arUrl['scheme'], $arUrl['host']); } else { - $url = $this->domainUrl; + $arUrl = parse_url($this->domainUrl); } - return $url; + return sprintf('%s://%s', $arUrl['scheme'], $arUrl['host']); } /** @@ -94,8 +122,9 @@ public function getAccessToken(): ?AccessToken * @param WebhookUrl $webhookUrl * * @return self + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException */ - public static function createForWebHook(WebhookUrl $webhookUrl): self + public static function createFromWebhook(WebhookUrl $webhookUrl): self { return new self( $webhookUrl, @@ -111,8 +140,9 @@ public static function createForWebHook(WebhookUrl $webhookUrl): self * @param string $domainUrl * * @return self + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException */ - public static function createForOAuth(AccessToken $accessToken, ApplicationProfile $applicationProfile, string $domainUrl): self + public static function createFromOAuth(AccessToken $accessToken, ApplicationProfile $applicationProfile, string $domainUrl): self { return new self( null, @@ -121,4 +151,20 @@ public static function createForOAuth(AccessToken $accessToken, ApplicationProfi $domainUrl ); } + + /** + * @param \Bitrix24\SDK\Application\Requests\Placement\PlacementRequest $placementRequest + * @param \Bitrix24\SDK\Core\Credentials\ApplicationProfile $applicationProfile + * + * @return self + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public static function createFromPlacementRequest(PlacementRequest $placementRequest, ApplicationProfile $applicationProfile): self + { + return self::createFromOAuth( + $placementRequest->getAccessToken(), + $applicationProfile, + $placementRequest->getDomainUrl() + ); + } } \ No newline at end of file diff --git a/src/Core/Credentials/Scope.php b/src/Core/Credentials/Scope.php index 3ddda1fa..7a6117bb 100644 --- a/src/Core/Credentials/Scope.php +++ b/src/Core/Credentials/Scope.php @@ -17,11 +17,12 @@ class Scope * @var string[] */ protected array $availableScope = [ - 'app', 'bizproc', 'calendar', 'call', + 'cashbox', 'catalog', + 'configuration.import', 'contact_center', 'crm', 'delivery', @@ -31,6 +32,7 @@ class Scope 'entity', 'faceid', 'forum', + 'iblock', 'im', 'imbot', 'imopenlines', @@ -47,15 +49,23 @@ class Scope 'pull', 'pull_channel', 'rating', + 'rpa', 'sale', + 'salescenter', 'smile', + 'socialnetwork', 'sonet_group', 'task', + 'tasks', 'tasks_extended', 'telephony', 'timeman', 'user', + 'user_basic', + 'user_brief', + 'user.userfield', 'userconsent', + 'userfieldconfig', ]; /** diff --git a/src/Core/Response/DTO/Pagination.php b/src/Core/Response/DTO/Pagination.php index eb0a5e4f..3f1816ef 100644 --- a/src/Core/Response/DTO/Pagination.php +++ b/src/Core/Response/DTO/Pagination.php @@ -11,14 +11,8 @@ */ class Pagination { - /** - * @var int|null - */ - private $nextItem; - /** - * @var int|null - */ - private $total; + private ?int $nextItem; + private ?int $total; /** * Pagination constructor. diff --git a/src/Core/Response/DTO/RenewedAccessToken.php b/src/Core/Response/DTO/RenewedAccessToken.php index a338c17a..3ed060da 100644 --- a/src/Core/Response/DTO/RenewedAccessToken.php +++ b/src/Core/Response/DTO/RenewedAccessToken.php @@ -15,7 +15,6 @@ class RenewedAccessToken { private AccessToken $accessToken; - private Scope $scope; private string $memberId; private string $clientEndpoint; private string $serverEndpoint; @@ -26,7 +25,6 @@ class RenewedAccessToken * RenewedAccessToken constructor. * * @param AccessToken $accessToken - * @param Scope $scope * @param string $memberId * @param string $clientEndpoint * @param string $serverEndpoint @@ -35,7 +33,6 @@ class RenewedAccessToken */ public function __construct( AccessToken $accessToken, - Scope $scope, string $memberId, string $clientEndpoint, string $serverEndpoint, @@ -43,7 +40,6 @@ public function __construct( string $domain ) { $this->accessToken = $accessToken; - $this->scope = $scope; $this->memberId = $memberId; $this->clientEndpoint = $clientEndpoint; $this->serverEndpoint = $serverEndpoint; @@ -59,14 +55,6 @@ public function getAccessToken(): AccessToken return $this->accessToken; } - /** - * @return Scope - */ - public function getScope(): Scope - { - return $this->scope; - } - /** * @return string */ @@ -111,13 +99,11 @@ public function getDomain(): string * @param array $response * * @return self - * @throws \Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException */ public static function initFromArray(array $response): self { return new self( AccessToken::initFromArray($response), - new Scope(explode(',', (string)$response['scope'])), (string)$response['member_id'], (string)$response['client_endpoint'], (string)$response['server_endpoint'], @@ -125,16 +111,4 @@ public static function initFromArray(array $response): self (string)$response['domain'] ); } -} - -//{ -// "access_token": "s1morf609228iwyjjpvfv6wsvuja4p8u", -// "refresh_token": "4f9k4jpmg13usmybzuqknt2v9fh0q6rl", -// "expires_in": 3600, -// "scope": "app", -// "member_id": "a223c6b3710f85df22e9377d6c4f7553", -// "client_endpoint": "https://portal.bitrix24.com/rest/", -// "server_endpoint": "https://oauth.bitrix.info/rest/", -// "domain": "oauth.bitrix.info", -// "status": "T" -//} \ No newline at end of file +} \ No newline at end of file diff --git a/src/Core/Response/DTO/ResponseData.php b/src/Core/Response/DTO/ResponseData.php index 655925fe..f50484ff 100644 --- a/src/Core/Response/DTO/ResponseData.php +++ b/src/Core/Response/DTO/ResponseData.php @@ -11,18 +11,18 @@ */ class ResponseData { - protected Result $result; + protected array $result; protected Time $time; protected Pagination $pagination; /** * ResponseData constructor. * - * @param Result $result + * @param array $result * @param Time $time * @param Pagination $pagination */ - public function __construct(Result $result, Time $time, Pagination $pagination) + public function __construct(array $result, Time $time, Pagination $pagination) { $this->result = $result; $this->time = $time; @@ -46,9 +46,9 @@ public function getTime(): Time } /** - * @return Result + * @return array */ - public function getResult(): Result + public function getResult(): array { return $this->result; } diff --git a/src/Core/Response/DTO/ResponseDataCollection.php b/src/Core/Response/DTO/ResponseDataCollection.php deleted file mode 100644 index da7d35f3..00000000 --- a/src/Core/Response/DTO/ResponseDataCollection.php +++ /dev/null @@ -1,18 +0,0 @@ -result = $result; - } - - /** - * @return array - */ - public function getResultData(): array - { - return $this->result; - } -} \ No newline at end of file diff --git a/src/Core/Response/DTO/Time.php b/src/Core/Response/DTO/Time.php index 3d41ec45..e1302aa1 100644 --- a/src/Core/Response/DTO/Time.php +++ b/src/Core/Response/DTO/Time.php @@ -4,6 +4,8 @@ namespace Bitrix24\SDK\Core\Response\DTO; +use DateTimeImmutable; + /** * Class Time * @@ -11,12 +13,22 @@ */ class Time { - protected float $start; - protected float $finish; - protected float $duration; - protected float $processing; - protected \DateTimeImmutable $dateStart; - protected \DateTimeImmutable $dateFinish; + private float $start; + private float $finish; + private float $duration; + private float $processing; + /** + * @var float $operating sum of query execution time + * @see https://training.bitrix24.com/rest_help/rest_sum/operating.php + */ + private float $operating; // time in seconds + private DateTimeImmutable $dateStart; + private DateTimeImmutable $dateFinish; + /** + * @var int|null time to reset nearest limit part + * @see https://training.bitrix24.com/rest_help/rest_sum/operating.php + */ + private ?int $operatingResetAt; /** * Time constructor. @@ -25,23 +37,29 @@ class Time * @param float $finish * @param float $duration * @param float $processing + * @param float $operating * @param \DateTimeImmutable $dateStart * @param \DateTimeImmutable $dateFinish + * @param int|null $operatingResetAt */ public function __construct( float $start, float $finish, float $duration, float $processing, - \DateTimeImmutable $dateStart, - \DateTimeImmutable $dateFinish + float $operating, + DateTimeImmutable $dateStart, + DateTimeImmutable $dateFinish, + ?int $operatingResetAt ) { $this->start = $start; $this->finish = $finish; $this->duration = $duration; $this->processing = $processing; + $this->operating = $operating; $this->dateStart = $dateStart; $this->dateFinish = $dateFinish; + $this->operatingResetAt = $operatingResetAt; } /** @@ -76,10 +94,26 @@ public function getProcessing(): float return $this->processing; } + /** + * @return float + */ + public function getOperating(): float + { + return $this->operating; + } + + /** + * @return int|null + */ + public function getOperatingResetAt(): ?int + { + return $this->operatingResetAt; + } + /** * @return \DateTimeImmutable */ - public function getDateStart(): \DateTimeImmutable + public function getDateStart(): DateTimeImmutable { return $this->dateStart; } @@ -87,7 +121,7 @@ public function getDateStart(): \DateTimeImmutable /** * @return \DateTimeImmutable */ - public function getDateFinish(): \DateTimeImmutable + public function getDateFinish(): DateTimeImmutable { return $this->dateFinish; } @@ -105,8 +139,10 @@ public static function initFromResponse(array $response): self (float)$response['finish'], (float)$response['duration'], (float)$response['processing'], - new \DateTimeImmutable($response['date_start']), - new \DateTimeImmutable($response['date_finish']) + (float)$response['operating'], + new DateTimeImmutable($response['date_start']), + new DateTimeImmutable($response['date_finish']), + $response['operating_reset_at'] ?? null ); } } \ No newline at end of file diff --git a/src/Core/Response/Response.php b/src/Core/Response/Response.php index 81f53b58..75566327 100644 --- a/src/Core/Response/Response.php +++ b/src/Core/Response/Response.php @@ -21,9 +21,9 @@ class Response { protected ResponseInterface $httpResponse; - protected LoggerInterface $logger; protected ?DTO\ResponseData $responseData; protected Command $apiCommand; + protected LoggerInterface $logger; /** * Response constructor. @@ -109,7 +109,7 @@ public function getResponseData(): DTO\ResponseData } $this->responseData = new DTO\ResponseData( - new DTO\Result($responseResult['result']), + $responseResult['result'], DTO\Time::initFromResponse($responseResult['time']), new DTO\Pagination($nextItem, $total) ); diff --git a/src/Core/Result/AbstractItem.php b/src/Core/Result/AbstractItem.php index ca18e485..a3e3e409 100644 --- a/src/Core/Result/AbstractItem.php +++ b/src/Core/Result/AbstractItem.php @@ -4,14 +4,17 @@ namespace Bitrix24\SDK\Core\Result; +use ArrayIterator; use Bitrix24\SDK\Core\Exceptions\ImmutableResultViolationException; +use IteratorAggregate; +use Traversable; /** * Class AbstractItem * * @package Bitrix24\SDK\Core\Result */ -abstract class AbstractItem implements \IteratorAggregate +abstract class AbstractItem implements IteratorAggregate { protected array $data; @@ -71,9 +74,9 @@ public function __unset($offset) /** * {@inheritdoc} */ - public function getIterator() + public function getIterator():Traversable { - return new \ArrayIterator($this->data); + return new ArrayIterator($this->data); } /** diff --git a/src/Core/Result/AddedItemBatchResult.php b/src/Core/Result/AddedItemBatchResult.php index 793b8dca..14180bbe 100644 --- a/src/Core/Result/AddedItemBatchResult.php +++ b/src/Core/Result/AddedItemBatchResult.php @@ -29,6 +29,6 @@ public function getResponseData(): ResponseData public function getId(): int { - return (int)$this->getResponseData()->getResult()->getResultData()[0]; + return (int)$this->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Core/Result/AddedItemResult.php b/src/Core/Result/AddedItemResult.php index fad8366d..bb491edc 100644 --- a/src/Core/Result/AddedItemResult.php +++ b/src/Core/Result/AddedItemResult.php @@ -20,6 +20,6 @@ class AddedItemResult extends AbstractResult implements AddedItemIdResultInterfa */ public function getId(): int { - return (int)$this->getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + return (int)$this->getCoreResponse()->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Core/Result/DeletedItemBatchResult.php b/src/Core/Result/DeletedItemBatchResult.php index f8efe47b..d63e67ab 100644 --- a/src/Core/Result/DeletedItemBatchResult.php +++ b/src/Core/Result/DeletedItemBatchResult.php @@ -32,6 +32,6 @@ public function getResponseData(): ResponseData */ public function isSuccess(): bool { - return (bool)$this->getResponseData()->getResult()->getResultData()[0]; + return (bool)$this->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Core/Result/DeletedItemResult.php b/src/Core/Result/DeletedItemResult.php index 3770582e..4eb5b4c4 100644 --- a/src/Core/Result/DeletedItemResult.php +++ b/src/Core/Result/DeletedItemResult.php @@ -20,6 +20,6 @@ class DeletedItemResult extends AbstractResult implements DeletedItemResultInter */ public function isSuccess(): bool { - return (bool)$this->getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Core/Result/FieldsResult.php b/src/Core/Result/FieldsResult.php index e997af4f..b9d7b435 100644 --- a/src/Core/Result/FieldsResult.php +++ b/src/Core/Result/FieldsResult.php @@ -19,6 +19,6 @@ class FieldsResult extends AbstractResult */ public function getFieldsDescription(): array { - return $this->getCoreResponse()->getResponseData()->getResult()->getResultData(); + return $this->getCoreResponse()->getResponseData()->getResult(); } } \ No newline at end of file diff --git a/src/Core/Result/UpdatedItemBatchResult.php b/src/Core/Result/UpdatedItemBatchResult.php new file mode 100644 index 00000000..e36de654 --- /dev/null +++ b/src/Core/Result/UpdatedItemBatchResult.php @@ -0,0 +1,37 @@ +responseData = $responseData; + } + + /** + * @return \Bitrix24\SDK\Core\Response\DTO\ResponseData + */ + public function getResponseData(): ResponseData + { + return $this->responseData; + } + + /** + * @return bool + */ + public function isSuccess(): bool + { + return (bool)$this->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Core/Result/UpdatedItemResult.php b/src/Core/Result/UpdatedItemResult.php index 7ee545e9..1995f034 100644 --- a/src/Core/Result/UpdatedItemResult.php +++ b/src/Core/Result/UpdatedItemResult.php @@ -19,6 +19,6 @@ class UpdatedItemResult extends AbstractResult */ public function isSuccess(): bool { - return (bool)$this->getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Events/AuthTokenRenewedEvent.php b/src/Events/AuthTokenRenewedEvent.php index 96a6f1b1..3dcb0eb2 100644 --- a/src/Events/AuthTokenRenewedEvent.php +++ b/src/Events/AuthTokenRenewedEvent.php @@ -14,10 +14,7 @@ */ class AuthTokenRenewedEvent extends Event { - /** - * @var RenewedAccessToken - */ - private $renewedToken; + private RenewedAccessToken $renewedToken; /** * AuthTokenRenewedEvent constructor. diff --git a/src/Events/PortalDomainUrlChangedEvent.php b/src/Events/PortalDomainUrlChangedEvent.php new file mode 100644 index 00000000..dc948537 --- /dev/null +++ b/src/Events/PortalDomainUrlChangedEvent.php @@ -0,0 +1,39 @@ +oldDomainUrlHost = parse_url($oldDomainUrlHost, PHP_URL_HOST); + $this->newDomainUrlHost = parse_url($newDomainUrlHost, PHP_URL_HOST); + } + + /** + * @return string + */ + public function getOldDomainUrlHost(): string + { + return $this->oldDomainUrlHost; + } + + /** + * @return string + */ + public function getNewDomainUrlHost(): string + { + return $this->newDomainUrlHost; + } +} \ No newline at end of file diff --git a/src/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser.php b/src/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser.php index 696a08a9..093f2a62 100644 --- a/src/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser.php +++ b/src/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser.php @@ -21,19 +21,18 @@ public function __construct(array $httpClientResponseInfo) // time_starttransfer: 0.092s // ---------- // time_total: 0.164s - $this->networkTimings = [ // name lookup time in MICROSECONDS // https://curl.se/libcurl/c/CURLINFO_NAMELOOKUP_TIME.html // get the name lookup time // Time from the start until the name resolving was completed. // When a redirect is followed, the time from each request is added together. - 'namelookup_time_us' => $httpClientResponseInfo['namelookup_time_us'], + 'namelookup_time' => $httpClientResponseInfo['namelookup_time'], // total time in seconds from the start until the connection to the remote host (or proxy) was completed in MICROSECONDS // https://curl.se/libcurl/c/CURLINFO_CONNECT_TIME.html // When a redirect is followed, the time from each request is added together. - 'connect_time_us' => $httpClientResponseInfo['connect_time_us'], + 'connect_time' => $httpClientResponseInfo['connect_time'], // time until the SSL/SSH handshake is completed in MICROSECONDS // https://curl.se/libcurl/c/CURLINFO_APPCONNECT_TIME.html @@ -41,7 +40,7 @@ public function __construct(array $httpClientResponseInfo) // This time is most often close to the CURLINFO_PRETRANSFER_TIME time, except for cases such as HTTP pipelining // where the pretransfer time can be delayed due to waits in line for the pipeline and more. // When a redirect is followed, the time from each request is added together. - 'appconnect_time_us' => $httpClientResponseInfo['appconnect_time_us'], + 'appconnect_time' => $httpClientResponseInfo['appconnect_time'] ?? null, // time until the file transfer start in MICROSECONDS // https://curl.se/libcurl/c/CURLINFO_PRETRANSFER_TIME.html @@ -49,28 +48,28 @@ public function __construct(array $httpClientResponseInfo) // This time-stamp includes all pre-transfer commands and negotiations that are specific to the particular // protocol(s) involved. It includes the sending of the protocol- specific protocol instructions that triggers a transfer. // When a redirect is followed, the time from each request is added together. - 'pretransfer_time_us' => $httpClientResponseInfo['pretransfer_time_us'], + 'pretransfer_time' => $httpClientResponseInfo['pretransfer_time'], // time for all redirection steps in MICROSECONDS // https://curl.se/libcurl/c/CURLINFO_REDIRECT_TIME.html // it took for all redirection steps include name lookup, connect, pretransfer and transfer before // final transaction was started. // CURLINFO_REDIRECT_TIME contains the complete execution time for multiple redirections. - 'redirect_time_us' => $httpClientResponseInfo['redirect_time_us'], + 'redirect_time' => $httpClientResponseInfo['redirect_time'], // time until the first byte is received in MICROSECONDS // it took from the start until the first byte is received by libcurl // https://curl.se/libcurl/c/CURLINFO_STARTTRANSFER_TIME.html // This includes CURLINFO_PRETRANSFER_TIME and also the time the server needs to calculate the result. // When a redirect is followed, the time from each request is added together. - 'starttransfer_time_us' => $httpClientResponseInfo['starttransfer_time_us'], + 'starttransfer_time' => $httpClientResponseInfo['starttransfer_time'], // total time of previous transfer in MICROSECONDS // https://curl.se/libcurl/c/CURLINFO_TOTAL_TIME.html // total time in seconds for the previous transfer, including name resolving, TCP connect etc. // The double represents the time in seconds, including fractions. // When a redirect is followed, the time from each request is added together. - 'total_time_us' => $httpClientResponseInfo['total_time_us'], + 'total_time' => $httpClientResponseInfo['total_time'], ]; } diff --git a/src/Services/AbstractService.php b/src/Services/AbstractService.php index cf20323f..a2ee2cfa 100644 --- a/src/Services/AbstractService.php +++ b/src/Services/AbstractService.php @@ -5,6 +5,8 @@ namespace Bitrix24\SDK\Services; use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Money\Currencies\ISOCurrencies; +use Money\Formatter\DecimalMoneyFormatter; use Psr\Log\LoggerInterface; /** @@ -19,16 +21,18 @@ abstract class AbstractService */ public CoreInterface $core; protected LoggerInterface $log; + protected DecimalMoneyFormatter $decimalMoneyFormatter; /** * AbstractService constructor. * - * @param CoreInterface $core + * @param CoreInterface $core * @param LoggerInterface $log */ public function __construct(CoreInterface $core, LoggerInterface $log) { $this->core = $core; $this->log = $log; + $this->decimalMoneyFormatter = new DecimalMoneyFormatter(new ISOCurrencies()); } } \ No newline at end of file diff --git a/src/Services/CRM/Activity/ActivityFetcherBuilder.php b/src/Services/CRM/Activity/ActivityFetcherBuilder.php new file mode 100644 index 00000000..e4508320 --- /dev/null +++ b/src/Services/CRM/Activity/ActivityFetcherBuilder.php @@ -0,0 +1,63 @@ +serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Activity\ReadModel\EmailFetcher($this->bulkItemsReader); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * @return \Bitrix24\SDK\Services\CRM\Activity\ReadModel\OpenLineFetcher + */ + public function openLineFetcher(): Activity\ReadModel\OpenLineFetcher + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Activity\ReadModel\OpenLineFetcher($this->bulkItemsReader); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * @return \Bitrix24\SDK\Services\CRM\Activity\ReadModel\VoximplantFetcher + */ + public function voximplantFetcher(): Activity\ReadModel\VoximplantFetcher + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Activity\ReadModel\VoximplantFetcher($this->bulkItemsReader); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * @return \Bitrix24\SDK\Services\CRM\Activity\ReadModel\WebFormFetcher + */ + public function webFormFetcher(): Activity\ReadModel\WebFormFetcher + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Activity\ReadModel\WebFormFetcher($this->bulkItemsReader); + } + + return $this->serviceCache[__METHOD__]; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/ReadModel/EmailFetcher.php b/src/Services/CRM/Activity/ReadModel/EmailFetcher.php new file mode 100644 index 00000000..2b42e249 --- /dev/null +++ b/src/Services/CRM/Activity/ReadModel/EmailFetcher.php @@ -0,0 +1,44 @@ +bulkItemsReader = $bulkItemsReader; + } + + /** + * @param array $order + * @param array $filter + * @param array $select + * @param int|null $limit + * + * @return EmailActivityItemResult[]|Generator + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function getList(array $order, array $filter, array $select, ?int $limit = null): Generator + { + $filter = array_merge($filter, [ + 'PROVIDER_ID' => 'CRM_EMAIL', + 'PROVIDER_TYPE_ID' => 'EMAIL', + ]); + + foreach ($this->bulkItemsReader->getTraversableList('crm.activity.list', $order, $filter, $select, $limit) as $cnt => $item) { + yield $cnt => new EmailActivityItemResult($item); + } + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/ReadModel/OpenLineFetcher.php b/src/Services/CRM/Activity/ReadModel/OpenLineFetcher.php new file mode 100644 index 00000000..baa946be --- /dev/null +++ b/src/Services/CRM/Activity/ReadModel/OpenLineFetcher.php @@ -0,0 +1,49 @@ +bulkItemsReader = $bulkItemsReader; + } + + /** + * @param array $order + * @param array $filter + * @param array $select + * @param int|null $openLineTypeId + * @param int|null $limit + * + * @return OpenLineActivityItemResult[]|Generator + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function getList(array $order, array $filter, array $select, ?int $openLineTypeId = null, ?int $limit = null): Generator + { + if ($openLineTypeId !== null) { + $filter = array_merge($filter, [ + 'PROVIDER_ID' => 'IMOPENLINES_SESSION', + 'PROVIDER_TYPE_ID' => $openLineTypeId, + ]); + } else { + $filter = array_merge($filter, ['PROVIDER_ID' => 'IMOPENLINES_SESSION']); + } + + foreach ($this->bulkItemsReader->getTraversableList('crm.activity.list', $order, $filter, $select, $limit) as $cnt => $item) { + yield $cnt => new OpenLineActivityItemResult($item); + } + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/ReadModel/VoximplantFetcher.php b/src/Services/CRM/Activity/ReadModel/VoximplantFetcher.php new file mode 100644 index 00000000..1ed02368 --- /dev/null +++ b/src/Services/CRM/Activity/ReadModel/VoximplantFetcher.php @@ -0,0 +1,44 @@ +bulkItemsReader = $bulkItemsReader; + } + + /** + * @param array $order + * @param array $filter + * @param array $select + * @param int|null $limit + * + * @return \Bitrix24\SDK\Services\CRM\Activity\Result\ActivityItemResult[]|Generator + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function getList(array $order, array $filter, array $select, ?int $limit = null): Generator + { + $filter = array_merge($filter, [ + 'PROVIDER_ID' => 'VOXIMPLANT_CALL', + 'PROVIDER_TYPE_ID' => 'CALL', + ]); + + foreach ($this->bulkItemsReader->getTraversableList('crm.activity.list', $order, $filter, $select, $limit) as $cnt => $item) { + yield $cnt => new ActivityItemResult($item); + } + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/ReadModel/WebFormFetcher.php b/src/Services/CRM/Activity/ReadModel/WebFormFetcher.php new file mode 100644 index 00000000..5d4c0662 --- /dev/null +++ b/src/Services/CRM/Activity/ReadModel/WebFormFetcher.php @@ -0,0 +1,48 @@ +bulkItemsReader = $bulkItemsReader; + } + + /** + * @param array $order + * @param array $filter + * @param array $select + * @param int|null $webFormId + * @param int|null $limit + * + * @return WebFormActivityItemResult[]|Generator + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function getList(array $order, array $filter, array $select, ?int $webFormId = null, ?int $limit = null): Generator + { + if ($webFormId !== null) { + $filter = array_merge($filter, [ + 'PROVIDER_ID' => 'CRM_WEBFORM', + 'PROVIDER_TYPE_ID' => $webFormId, + ]); + } else { + $filter = array_merge($filter, ['PROVIDER_ID' => 'CRM_WEBFORM']); + } + foreach ($this->bulkItemsReader->getTraversableList('crm.activity.list', $order, $filter, $select, $limit) as $cnt => $item) { + yield $cnt => new WebFormActivityItemResult($item); + } + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/Result/ActivitiesResult.php b/src/Services/CRM/Activity/Result/ActivitiesResult.php new file mode 100644 index 00000000..ce52ce3d --- /dev/null +++ b/src/Services/CRM/Activity/Result/ActivitiesResult.php @@ -0,0 +1,26 @@ +getCoreResponse()->getResponseData()->getResult() as $item) { + $res[] = new ActivityItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/Result/ActivityItemResult.php b/src/Services/CRM/Activity/Result/ActivityItemResult.php new file mode 100644 index 00000000..72062fd8 --- /dev/null +++ b/src/Services/CRM/Activity/Result/ActivityItemResult.php @@ -0,0 +1,59 @@ +getCoreResponse()->getResponseData()->getResult()); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/Result/Email/EmailActivityItemResult.php b/src/Services/CRM/Activity/Result/Email/EmailActivityItemResult.php new file mode 100644 index 00000000..c3056932 --- /dev/null +++ b/src/Services/CRM/Activity/Result/Email/EmailActivityItemResult.php @@ -0,0 +1,22 @@ +data[$offset]); + } + + return parent::__get($offset); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/Result/Email/EmailMeta.php b/src/Services/CRM/Activity/Result/Email/EmailMeta.php new file mode 100644 index 00000000..939672b8 --- /dev/null +++ b/src/Services/CRM/Activity/Result/Email/EmailMeta.php @@ -0,0 +1,19 @@ +data)) { + return new EmailMeta($this->data[$offset]); + } + + return null; + } + + return parent::__get($offset); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/Result/OpenLine/OpenLineActivityItemResult.php b/src/Services/CRM/Activity/Result/OpenLine/OpenLineActivityItemResult.php new file mode 100644 index 00000000..caa83230 --- /dev/null +++ b/src/Services/CRM/Activity/Result/OpenLine/OpenLineActivityItemResult.php @@ -0,0 +1,18 @@ +PROVIDER_PARAMS['USER_CODE']); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/Result/OpenLine/OpenLineProviderParams.php b/src/Services/CRM/Activity/Result/OpenLine/OpenLineProviderParams.php new file mode 100644 index 00000000..5920829f --- /dev/null +++ b/src/Services/CRM/Activity/Result/OpenLine/OpenLineProviderParams.php @@ -0,0 +1,43 @@ +userCode = $userCode; + } + + /** + * @return string + */ + public function getUserCode(): string + { + return $this->userCode; + } + + /** + * @return int + */ + public function getBitrix24UserId(): int + { + return (int)explode('|', $this->getUserCode())[3]; + } + + /** + * @return string + */ + public function getExternalSystemUserId(): string + { + return explode('|', $this->getUserCode())[2]; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/Result/WebForm/VisitedPageItem.php b/src/Services/CRM/Activity/Result/WebForm/VisitedPageItem.php new file mode 100644 index 00000000..c479f8f7 --- /dev/null +++ b/src/Services/CRM/Activity/Result/WebForm/VisitedPageItem.php @@ -0,0 +1,18 @@ +PROVIDER_PARAMS['FIELDS'], + new WebFormMetadata( + $this->PROVIDER_PARAMS['FORM']['IS_USED_USER_CONSENT'], + $this->PROVIDER_PARAMS['FORM']['AGREEMENTS'], + $this->PROVIDER_PARAMS['FORM']['IP'], + $this->PROVIDER_PARAMS['FORM']['LINK'] + ), + $this->PROVIDER_PARAMS['VISITED_PAGES'], + ); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/Result/WebForm/WebFormFieldItem.php b/src/Services/CRM/Activity/Result/WebForm/WebFormFieldItem.php new file mode 100644 index 00000000..1fc1572e --- /dev/null +++ b/src/Services/CRM/Activity/Result/WebForm/WebFormFieldItem.php @@ -0,0 +1,20 @@ +isUsedUserConsent = $isUsedUserConsent; + $this->agreements = $agreements; + $this->ip = $ip; + $this->link = $link; + } + + /** + * @return bool + */ + public function isUsedUserConsent(): bool + { + return $this->isUsedUserConsent; + } + + /** + * @return array + */ + public function getAgreements(): array + { + return $this->agreements; + } + + /** + * @return string + */ + public function getIp(): string + { + return $this->ip; + } + + /** + * @return string + */ + public function getLink(): string + { + return $this->link; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/Result/WebForm/WebFormProviderParams.php b/src/Services/CRM/Activity/Result/WebForm/WebFormProviderParams.php new file mode 100644 index 00000000..d61998a1 --- /dev/null +++ b/src/Services/CRM/Activity/Result/WebForm/WebFormProviderParams.php @@ -0,0 +1,59 @@ +fields = $fields; + $this->webForm = $webForm; + $this->visitedPages = $visitedPages; + } + + /** + * @return WebFormFieldItem[] + */ + public function getFields(): array + { + $res = []; + foreach ($this->fields as $field) { + $res[] = new WebFormFieldItem($field); + } + + return $res; + } + + /** + * @return \Bitrix24\SDK\Services\CRM\Activity\Result\WebForm\WebFormMetadata + */ + public function getWebForm(): WebFormMetadata + { + return $this->webForm; + } + + /** + * @return VisitedPageItem[] + */ + public function getVisitedPages(): array + { + $res = []; + foreach ($this->visitedPages as $page) { + $res[] = new VisitedPageItem($page); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/Service/Activity.php b/src/Services/CRM/Activity/Service/Activity.php new file mode 100644 index 00000000..9ccde4f7 --- /dev/null +++ b/src/Services/CRM/Activity/Service/Activity.php @@ -0,0 +1,413 @@ +batch = $batch; + } + + /** + * Creates and adds a new activity. + * + * @link https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_add.php + * + * @param array{ + * ID?: int, + * OWNER_ID?: int, + * OWNER_TYPE_ID?: string, + * TYPE_ID?: string, + * PROVIDER_ID?: string, + * PROVIDER_TYPE_ID?: string, + * PROVIDER_GROUP_ID?: string, + * ASSOCIATED_ENTITY_ID?: int, + * SUBJECT?: string, + * START_TIME?: string, + * END_TIME?: string, + * DEADLINE?: string, + * COMPLETED?: string, + * STATUS?: string, + * RESPONSIBLE_ID?: string, + * PRIORITY?: string, + * NOTIFY_TYPE?: string, + * NOTIFY_VALUE?: int, + * DESCRIPTION?: string, + * DESCRIPTION_TYPE?: string, + * DIRECTION?: string, + * LOCATION?: string, + * CREATED?: string, + * AUTHOR_ID?: string, + * LAST_UPDATED?: string, + * EDITOR_ID?: string, + * SETTINGS?: string, + * ORIGIN_ID?: string, + * ORIGINATOR_ID?: string, + * RESULT_STATUS?: int, + * RESULT_STREAM?: int, + * RESULT_SOURCE_ID?: string, + * PROVIDER_PARAMS?: string, + * PROVIDER_DATA?: string, + * RESULT_MARK?: int, + * RESULT_VALUE?: string, + * RESULT_SUM?: string, + * RESULT_CURRENCY_ID?: string, + * AUTOCOMPLETE_RULE?: int, + * BINDINGS?: string, + * COMMUNICATIONS?: string, + * FILES?: string, + * WEBDAV_ELEMENTS?: string, + * } $fields + * + * @return AddedItemResult + * @throws BaseException + * @throws TransportException + */ + public function add(array $fields): AddedItemResult + { + return new AddedItemResult( + $this->core->call( + 'crm.activity.add', + [ + 'fields' => $fields, + ] + ) + ); + } + + /** + * Deletes the specified activity and all the associated objects. + * + * @link https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_delete.php + * + * @param int $itemId + * + * @return DeletedItemResult + * @throws BaseException + * @throws TransportException + */ + public function delete(int $itemId): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call( + 'crm.activity.delete', + [ + 'id' => $itemId, + ] + ) + ); + } + + /** + * Returns the description of activity + * + * @link https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_fields.php + * + * @return FieldsResult + * @throws BaseException + * @throws TransportException + */ + public function fields(): FieldsResult + { + return new FieldsResult($this->core->call('crm.activity.fields')); + } + + /** + * Returns activity by the specified activity ID + * + * @link https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_get.php + * + * @param int $entityId + * + * @return ActivityResult + * @throws BaseException + * @throws TransportException + */ + public function get(int $entityId): ActivityResult + { + return new ActivityResult( + $this->core->call( + 'crm.activity.get', + [ + 'id' => $entityId, + ] + ) + ); + } + + /** + * Returns a list of activity selected by the filter specified as the parameter. See the example for the filter notation. + * + * @link https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_list.php + * + * @param array{ + * ID?: int, + * OWNER_ID?: int, + * OWNER_TYPE_ID?: string, + * TYPE_ID?: string, + * PROVIDER_ID?: string, + * PROVIDER_TYPE_ID?: string, + * PROVIDER_GROUP_ID?: string, + * ASSOCIATED_ENTITY_ID?: int, + * SUBJECT?: string, + * START_TIME?: string, + * END_TIME?: string, + * DEADLINE?: string, + * COMPLETED?: string, + * STATUS?: string, + * RESPONSIBLE_ID?: string, + * PRIORITY?: string, + * NOTIFY_TYPE?: string, + * NOTIFY_VALUE?: int, + * DESCRIPTION?: string, + * DESCRIPTION_TYPE?: string, + * DIRECTION?: string, + * LOCATION?: string, + * CREATED?: string, + * AUTHOR_ID?: string, + * LAST_UPDATED?: string, + * EDITOR_ID?: string, + * SETTINGS?: string, + * ORIGIN_ID?: string, + * ORIGINATOR_ID?: string, + * RESULT_STATUS?: int, + * RESULT_STREAM?: int, + * RESULT_SOURCE_ID?: string, + * PROVIDER_PARAMS?: string, + * PROVIDER_DATA?: string, + * RESULT_MARK?: int, + * RESULT_VALUE?: string, + * RESULT_SUM?: string, + * RESULT_CURRENCY_ID?: string, + * AUTOCOMPLETE_RULE?: int, + * BINDINGS?: string, + * COMMUNICATIONS?: string, + * FILES?: string, + * WEBDAV_ELEMENTS?: string, + * } $order + * + * @param array{ + * ID?: int, + * OWNER_ID?: int, + * OWNER_TYPE_ID?: string, + * TYPE_ID?: string, + * PROVIDER_ID?: string, + * PROVIDER_TYPE_ID?: string, + * PROVIDER_GROUP_ID?: string, + * ASSOCIATED_ENTITY_ID?: int, + * SUBJECT?: string, + * START_TIME?: string, + * END_TIME?: string, + * DEADLINE?: string, + * COMPLETED?: string, + * STATUS?: string, + * RESPONSIBLE_ID?: string, + * PRIORITY?: string, + * NOTIFY_TYPE?: string, + * NOTIFY_VALUE?: int, + * DESCRIPTION?: string, + * DESCRIPTION_TYPE?: string, + * DIRECTION?: string, + * LOCATION?: string, + * CREATED?: string, + * AUTHOR_ID?: string, + * LAST_UPDATED?: string, + * EDITOR_ID?: string, + * SETTINGS?: string, + * ORIGIN_ID?: string, + * ORIGINATOR_ID?: string, + * RESULT_STATUS?: int, + * RESULT_STREAM?: int, + * RESULT_SOURCE_ID?: string, + * PROVIDER_PARAMS?: string, + * PROVIDER_DATA?: string, + * RESULT_MARK?: int, + * RESULT_VALUE?: string, + * RESULT_SUM?: string, + * RESULT_CURRENCY_ID?: string, + * AUTOCOMPLETE_RULE?: int, + * BINDINGS?: string, + * COMMUNICATIONS?: string, + * FILES?: string, + * WEBDAV_ELEMENTS?: string, + * } $filter + * + * @param array $select = ['ID','OWNER_ID','OWNER_TYPE_ID','TYPE_ID','PROVIDER_ID','PROVIDER_TYPE_ID','PROVIDER_GROUP_ID','ASSOCIATED_ENTITY_ID','SUBJECT','START_TIME','END_TIME','DEADLINE','COMPLETED','STATUS','RESPONSIBLE_ID','PRIORITY','NOTIFY_TYPE','NOTIFY_VALUE','DESCRIPTION','DESCRIPTION_TYPE','DIRECTION','LOCATION','CREATED','AUTHOR_ID','LAST_UPDATED','EDITOR_ID','SETTINGS','ORIGIN_ID','ORIGINATOR_ID','RESULT_STATUS','RESULT_STREAM','RESULT_SOURCE_ID','PROVIDER_PARAMS','PROVIDER_DATA','RESULT_MARK','RESULT_VALUE','RESULT_SUM','RESULT_CURRENCY_ID','AUTOCOMPLETE_RULE','BINDINGS','COMMUNICATIONS','FILES','WEBDAV_ELEMENTS','COMMUNICATIONS'] + * @param int $start + * + * @return ActivitiesResult + * @throws BaseException + * @throws TransportException + */ + public function list(array $order, array $filter, array $select, int $start): ActivitiesResult + { + return new ActivitiesResult( + $this->core->call( + 'crm.activity.list', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $start, + ] + ) + ); + } + + /** + * Updates the specified (existing) activity. + * + * @see https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_update.php + * + * @param int $itemId + * @param array{ + * ID?: int, + * OWNER_ID?: int, + * OWNER_TYPE_ID?: string, + * TYPE_ID?: string, + * PROVIDER_ID?: string, + * PROVIDER_TYPE_ID?: string, + * PROVIDER_GROUP_ID?: string, + * ASSOCIATED_ENTITY_ID?: int, + * SUBJECT?: string, + * START_TIME?: string, + * END_TIME?: string, + * DEADLINE?: string, + * COMPLETED?: string, + * STATUS?: string, + * RESPONSIBLE_ID?: string, + * PRIORITY?: string, + * NOTIFY_TYPE?: string, + * NOTIFY_VALUE?: int, + * DESCRIPTION?: string, + * DESCRIPTION_TYPE?: string, + * DIRECTION?: string, + * LOCATION?: string, + * CREATED?: string, + * AUTHOR_ID?: string, + * LAST_UPDATED?: string, + * EDITOR_ID?: string, + * SETTINGS?: string, + * ORIGIN_ID?: string, + * ORIGINATOR_ID?: string, + * RESULT_STATUS?: int, + * RESULT_STREAM?: int, + * RESULT_SOURCE_ID?: string, + * PROVIDER_PARAMS?: string, + * PROVIDER_DATA?: string, + * RESULT_MARK?: int, + * RESULT_VALUE?: string, + * RESULT_SUM?: string, + * RESULT_CURRENCY_ID?: string, + * AUTOCOMPLETE_RULE?: int, + * BINDINGS?: string, + * COMMUNICATIONS?: string, + * FILES?: string, + * WEBDAV_ELEMENTS?: string, + * } $fields + * + * @return UpdatedItemResult + * @throws BaseException + * @throws TransportException + */ + public function update(int $itemId, array $fields): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call( + 'crm.activity.update', + [ + 'id' => $itemId, + 'fields' => $fields, + ] + ) + ); + } + + /** + * Count activity by filter + * + * @param array{ + * ID?: int, + * OWNER_ID?: int, + * OWNER_TYPE_ID?: string, + * TYPE_ID?: string, + * PROVIDER_ID?: string, + * PROVIDER_TYPE_ID?: string, + * PROVIDER_GROUP_ID?: string, + * ASSOCIATED_ENTITY_ID?: int, + * SUBJECT?: string, + * START_TIME?: string, + * END_TIME?: string, + * DEADLINE?: string, + * COMPLETED?: string, + * STATUS?: string, + * RESPONSIBLE_ID?: string, + * PRIORITY?: string, + * NOTIFY_TYPE?: string, + * NOTIFY_VALUE?: int, + * DESCRIPTION?: string, + * DESCRIPTION_TYPE?: string, + * DIRECTION?: string, + * LOCATION?: string, + * CREATED?: string, + * AUTHOR_ID?: string, + * LAST_UPDATED?: string, + * EDITOR_ID?: string, + * SETTINGS?: string, + * ORIGIN_ID?: string, + * ORIGINATOR_ID?: string, + * RESULT_STATUS?: int, + * RESULT_STREAM?: int, + * RESULT_SOURCE_ID?: string, + * PROVIDER_PARAMS?: string, + * PROVIDER_DATA?: string, + * RESULT_MARK?: int, + * RESULT_VALUE?: string, + * RESULT_SUM?: string, + * RESULT_CURRENCY_ID?: string, + * AUTOCOMPLETE_RULE?: int, + * BINDINGS?: string, + * COMMUNICATIONS?: string, + * FILES?: string, + * WEBDAV_ELEMENTS?: string, + * } $filter + * + * @return int + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function countByFilter(array $filter = []): int + { + return $this->list([], $filter, ['ID'], 1)->getCoreResponse()->getResponseData()->getPagination()->getTotal(); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/Service/Batch.php b/src/Services/CRM/Activity/Service/Batch.php new file mode 100644 index 00000000..d176a977 --- /dev/null +++ b/src/Services/CRM/Activity/Service/Batch.php @@ -0,0 +1,216 @@ +|ActivityItemResult[] + * @throws BaseException + */ + public function list(array $order, array $filter, array $select, ?int $limit = null): Generator + { + $this->log->debug( + 'list', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'limit' => $limit, + ] + ); + foreach ($this->batch->getTraversableList('crm.activity.list', $order, $filter, $select, $limit) as $key => $value) { + yield $key => new ActivityItemResult($value); + } + } + + /** + * Batch adding activity items + * + * @param array $activities + * + * @return \Generator + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function add(array $activities): Generator + { + $items = []; + foreach ($activities as $activity) { + $items[] = [ + 'fields' => $activity, + ]; + } + foreach ($this->batch->addEntityItems('crm.activity.add', $items) as $key => $item) { + yield $key => new AddedItemBatchResult($item); + } + } + + /** + * Batch delete activity items + * + * @param int[] $itemId + * + * @return \Generator|\Bitrix24\SDK\Core\Contracts\DeletedItemResultInterface[] + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function delete(array $itemId): Generator + { + foreach ($this->batch->deleteEntityItems('crm.activity.delete', $itemId) as $key => $item) { + yield $key => new DeletedItemBatchResult($item); + } + } +} \ No newline at end of file diff --git a/src/Services/CRM/CRMServiceBuilder.php b/src/Services/CRM/CRMServiceBuilder.php index 82b5040e..7bd84b03 100644 --- a/src/Services/CRM/CRMServiceBuilder.php +++ b/src/Services/CRM/CRMServiceBuilder.php @@ -170,4 +170,53 @@ public function userfield(): Userfield\Service\Userfield return $this->serviceCache[__METHOD__]; } + + /** + * @return Lead\Service\Lead + */ + public function lead(): Lead\Service\Lead + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Lead\Service\Lead( + new Lead\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * @return Activity\Service\Activity + */ + public function activity(): Activity\Service\Activity + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Activity\Service\Activity( + new Activity\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * @return Activity\ActivityFetcherBuilder + */ + public function activityFetcher(): Activity\ActivityFetcherBuilder + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Activity\ActivityFetcherBuilder( + $this->core, + $this->batch, + $this->bulkItemsReader, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } } \ No newline at end of file diff --git a/src/Services/CRM/Contact/Result/ContactResult.php b/src/Services/CRM/Contact/Result/ContactResult.php index 4d58a917..4999cbdc 100644 --- a/src/Services/CRM/Contact/Result/ContactResult.php +++ b/src/Services/CRM/Contact/Result/ContactResult.php @@ -16,6 +16,6 @@ class ContactResult extends AbstractResult { public function contact(): ContactItemResult { - return new ContactItemResult($this->getCoreResponse()->getResponseData()->getResult()->getResultData()); + return new ContactItemResult($this->getCoreResponse()->getResponseData()->getResult()); } } \ No newline at end of file diff --git a/src/Services/CRM/Contact/Result/ContactUserfieldResult.php b/src/Services/CRM/Contact/Result/ContactUserfieldResult.php index 253b4b34..d1b50369 100644 --- a/src/Services/CRM/Contact/Result/ContactUserfieldResult.php +++ b/src/Services/CRM/Contact/Result/ContactUserfieldResult.php @@ -13,6 +13,6 @@ class ContactUserfieldResult extends AbstractResult */ public function userfieldItem(): ContactUserfieldItemResult { - return new ContactUserfieldItemResult($this->getCoreResponse()->getResponseData()->getResult()->getResultData()); + return new ContactUserfieldItemResult($this->getCoreResponse()->getResponseData()->getResult()); } } \ No newline at end of file diff --git a/src/Services/CRM/Contact/Result/ContactUserfieldsResult.php b/src/Services/CRM/Contact/Result/ContactUserfieldsResult.php index fc583cb4..30dbc44f 100644 --- a/src/Services/CRM/Contact/Result/ContactUserfieldsResult.php +++ b/src/Services/CRM/Contact/Result/ContactUserfieldsResult.php @@ -16,7 +16,7 @@ class ContactUserfieldsResult extends AbstractResult public function getUserfields(): array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { $res[] = new ContactUserfieldItemResult($item); } diff --git a/src/Services/CRM/Contact/Result/ContactsResult.php b/src/Services/CRM/Contact/Result/ContactsResult.php index 2e8748f2..82a0b2a4 100644 --- a/src/Services/CRM/Contact/Result/ContactsResult.php +++ b/src/Services/CRM/Contact/Result/ContactsResult.php @@ -22,7 +22,7 @@ class ContactsResult extends AbstractResult public function getContacts(): array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { $res[] = new ContactItemResult($item); } diff --git a/src/Services/CRM/Contact/Service/Batch.php b/src/Services/CRM/Contact/Service/Batch.php index 55172488..696720a2 100644 --- a/src/Services/CRM/Contact/Service/Batch.php +++ b/src/Services/CRM/Contact/Service/Batch.php @@ -6,6 +6,7 @@ use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Result\AddedItemBatchResult; +use Bitrix24\SDK\Core\Result\DeletedItemBatchResult; use Bitrix24\SDK\Services\AbstractBatchService; use Bitrix24\SDK\Services\CRM\Contact\Result\ContactItemResult; use Generator; @@ -119,8 +120,8 @@ class Batch extends AbstractBatchService * WEB?: string, * IM?: string, * } $filter - * @param array $select = ['ID','HONORIFIC','NAME','SECOND_NAME','LAST_NAME','PHOTO','BIRTHDATE','TYPE_ID','SOURCE_ID','SOURCE_DESCRIPTION','POST','ADDRESS','ADDRESS_2','ADDRESS_CITY','ADDRESS_POSTAL_CODE','ADDRESS_REGION','ADDRESS_PROVINCE','ADDRESS_COUNTRY','ADDRESS_COUNTRY_CODE','ADDRESS_LOC_ADDR_ID','COMMENTS','OPENED','EXPORT','HAS_PHONE','HAS_EMAIL','HAS_IMOL','ASSIGNED_BY_ID','CREATED_BY_ID','MODIFY_BY_ID','DATE_CREATE','DATE_MODIFY','COMPANY_ID','COMPANY_IDS','LEAD_ID','ORIGINATOR_ID','ORIGIN_ID','ORIGIN_VERSION','FACE_ID','UTM_SOURCE','UTM_MEDIUM','UTM_CAMPAIGN','UTM_CONTENT','UTM_TERM','PHONE','EMAIL','WEB','IM'] - * @param int|null $limit + * @param array $select = ['ID','HONORIFIC','NAME','SECOND_NAME','LAST_NAME','PHOTO','BIRTHDATE','TYPE_ID','SOURCE_ID','SOURCE_DESCRIPTION','POST','ADDRESS','ADDRESS_2','ADDRESS_CITY','ADDRESS_POSTAL_CODE','ADDRESS_REGION','ADDRESS_PROVINCE','ADDRESS_COUNTRY','ADDRESS_COUNTRY_CODE','ADDRESS_LOC_ADDR_ID','COMMENTS','OPENED','EXPORT','HAS_PHONE','HAS_EMAIL','HAS_IMOL','ASSIGNED_BY_ID','CREATED_BY_ID','MODIFY_BY_ID','DATE_CREATE','DATE_MODIFY','COMPANY_ID','COMPANY_IDS','LEAD_ID','ORIGINATOR_ID','ORIGIN_ID','ORIGIN_VERSION','FACE_ID','UTM_SOURCE','UTM_MEDIUM','UTM_CAMPAIGN','UTM_CONTENT','UTM_TERM','PHONE','EMAIL','WEB','IM'] + * @param int|null $limit * * @return Generator * @throws BaseException @@ -130,10 +131,10 @@ public function list(array $order, array $filter, array $select, ?int $limit = n $this->log->debug( 'list', [ - 'order' => $order, + 'order' => $order, 'filter' => $filter, 'select' => $select, - 'limit' => $limit, + 'limit' => $limit, ] ); foreach ($this->batch->getTraversableList('crm.contact.list', $order, $filter, $select, $limit) as $key => $value) { @@ -208,4 +209,19 @@ public function add(array $contacts): Generator yield $key => new AddedItemBatchResult($item); } } + + /** + * Batch delete contact items + * + * @param int[] $contactId + * + * @return \Generator + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function delete(array $contactId): Generator + { + foreach ($this->batch->deleteEntityItems('crm.contact.delete', $contactId) as $key => $item) { + yield $key => new DeletedItemBatchResult($item); + } + } } \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealCategoriesResult.php b/src/Services/CRM/Deal/Result/DealCategoriesResult.php index f8d8eee5..9d90c2bc 100644 --- a/src/Services/CRM/Deal/Result/DealCategoriesResult.php +++ b/src/Services/CRM/Deal/Result/DealCategoriesResult.php @@ -22,7 +22,7 @@ class DealCategoriesResult extends AbstractResult public function getDealCategories(): array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $dealCategory) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $dealCategory) { $res[] = new DealCategoryItemResult($dealCategory); } diff --git a/src/Services/CRM/Deal/Result/DealCategoryResult.php b/src/Services/CRM/Deal/Result/DealCategoryResult.php index e146c865..53d6867e 100644 --- a/src/Services/CRM/Deal/Result/DealCategoryResult.php +++ b/src/Services/CRM/Deal/Result/DealCategoryResult.php @@ -16,6 +16,6 @@ class DealCategoryResult extends AbstractResult { public function getDealCategoryFields(): DealCategoryItemResult { - return new DealCategoryItemResult($this->getCoreResponse()->getResponseData()->getResult()->getResultData()); + return new DealCategoryItemResult($this->getCoreResponse()->getResponseData()->getResult()); } } \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealCategoryStagesResult.php b/src/Services/CRM/Deal/Result/DealCategoryStagesResult.php index 9e2a51ea..c4f9ce82 100644 --- a/src/Services/CRM/Deal/Result/DealCategoryStagesResult.php +++ b/src/Services/CRM/Deal/Result/DealCategoryStagesResult.php @@ -23,7 +23,7 @@ class DealCategoryStagesResult extends AbstractResult public function getDealCategoryStages(): array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $deal) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $deal) { $res[] = new DealCategoryStageItemResult($deal); } diff --git a/src/Services/CRM/Deal/Result/DealCategoryStatusResult.php b/src/Services/CRM/Deal/Result/DealCategoryStatusResult.php index 68ea8e06..4236ec4b 100644 --- a/src/Services/CRM/Deal/Result/DealCategoryStatusResult.php +++ b/src/Services/CRM/Deal/Result/DealCategoryStatusResult.php @@ -21,6 +21,6 @@ class DealCategoryStatusResult extends AbstractResult */ public function getDealCategoryTypeId(): string { - return $this->getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + return $this->getCoreResponse()->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealContactItemsResult.php b/src/Services/CRM/Deal/Result/DealContactItemsResult.php index b0f639d8..6f8a40c1 100644 --- a/src/Services/CRM/Deal/Result/DealContactItemsResult.php +++ b/src/Services/CRM/Deal/Result/DealContactItemsResult.php @@ -21,7 +21,7 @@ class DealContactItemsResult extends AbstractResult public function getDealContacts(): array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $dealContact) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $dealContact) { $res[] = new DealContactItemResult($dealContact); } diff --git a/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php b/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php index 7104799b..06e78113 100644 --- a/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php +++ b/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php @@ -22,7 +22,7 @@ class DealProductRowItemsResult extends AbstractResult public function getProductRows(): array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $productRow) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $productRow) { $res[] = new DealProductRowItemResult($productRow); } diff --git a/src/Services/CRM/Deal/Result/DealResult.php b/src/Services/CRM/Deal/Result/DealResult.php index 91687e3a..4e9e01c3 100644 --- a/src/Services/CRM/Deal/Result/DealResult.php +++ b/src/Services/CRM/Deal/Result/DealResult.php @@ -16,6 +16,6 @@ class DealResult extends AbstractResult { public function deal(): DealItemResult { - return new DealItemResult($this->getCoreResponse()->getResponseData()->getResult()->getResultData()); + return new DealItemResult($this->getCoreResponse()->getResponseData()->getResult()); } } \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealUserfieldResult.php b/src/Services/CRM/Deal/Result/DealUserfieldResult.php index 60380774..4358c882 100644 --- a/src/Services/CRM/Deal/Result/DealUserfieldResult.php +++ b/src/Services/CRM/Deal/Result/DealUserfieldResult.php @@ -14,6 +14,6 @@ class DealUserfieldResult extends AbstractResult */ public function userfieldItem(): DealUserfieldItemResult { - return new DealUserfieldItemResult($this->getCoreResponse()->getResponseData()->getResult()->getResultData()); + return new DealUserfieldItemResult($this->getCoreResponse()->getResponseData()->getResult()); } } \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealUserfieldsResult.php b/src/Services/CRM/Deal/Result/DealUserfieldsResult.php index af523d1a..2aa60219 100644 --- a/src/Services/CRM/Deal/Result/DealUserfieldsResult.php +++ b/src/Services/CRM/Deal/Result/DealUserfieldsResult.php @@ -17,7 +17,7 @@ class DealUserfieldsResult extends AbstractResult public function getUserfields(): array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { $res[] = new DealUserfieldItemResult($item); } diff --git a/src/Services/CRM/Deal/Result/DealsResult.php b/src/Services/CRM/Deal/Result/DealsResult.php index 2481a7dd..3fdaa070 100644 --- a/src/Services/CRM/Deal/Result/DealsResult.php +++ b/src/Services/CRM/Deal/Result/DealsResult.php @@ -22,7 +22,7 @@ class DealsResult extends AbstractResult public function getDeals(): array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $deal) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $deal) { $res[] = new DealItemResult($deal); } diff --git a/src/Services/CRM/Deal/Service/Batch.php b/src/Services/CRM/Deal/Service/Batch.php index 81113517..e5351495 100644 --- a/src/Services/CRM/Deal/Service/Batch.php +++ b/src/Services/CRM/Deal/Service/Batch.php @@ -8,6 +8,7 @@ use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Result\AddedItemBatchResult; use Bitrix24\SDK\Core\Result\DeletedItemBatchResult; +use Bitrix24\SDK\Core\Result\UpdatedItemBatchResult; use Bitrix24\SDK\Services\CRM\Deal\Result\DealItemResult; use Generator; use Psr\Log\LoggerInterface; @@ -124,10 +125,10 @@ public function __construct(BatchInterface $batch, LoggerInterface $log) * UTM_CONTENT?: string, * UTM_TERM?: string, * } $filter - * @param array $select = ['ID','TITLE','TYPE_ID','CATEGORY_ID','STAGE_ID','STAGE_SEMANTIC_ID','IS_NEW','IS_RECURRING','IS_RETURN_CUSTOMER','IS_REPEATED_APPROACH','PROBABILITY','CURRENCY_ID','OPPORTUNITY','IS_MANUAL_OPPORTUNITY','TAX_VALUE','COMPANY_ID','CONTACT_ID','CONTACT_IDS','QUOTE_ID','BEGINDATE','CLOSEDATE','OPENED','CLOSED','COMMENTS','ASSIGNED_BY_ID','CREATED_BY_ID','MODIFY_BY_ID','DATE_CREATE','DATE_MODIFY','SOURCE_ID','SOURCE_DESCRIPTION','LEAD_ID','ADDITIONAL_INFO','LOCATION_ID','ORIGINATOR_ID','ORIGIN_ID','UTM_SOURCE','UTM_MEDIUM','UTM_CAMPAIGN','UTM_CONTENT','UTM_TERM'] - * @param int|null $limit + * @param array $select = ['ID','TITLE','TYPE_ID','CATEGORY_ID','STAGE_ID','STAGE_SEMANTIC_ID','IS_NEW','IS_RECURRING','IS_RETURN_CUSTOMER','IS_REPEATED_APPROACH','PROBABILITY','CURRENCY_ID','OPPORTUNITY','IS_MANUAL_OPPORTUNITY','TAX_VALUE','COMPANY_ID','CONTACT_ID','CONTACT_IDS','QUOTE_ID','BEGINDATE','CLOSEDATE','OPENED','CLOSED','COMMENTS','ASSIGNED_BY_ID','CREATED_BY_ID','MODIFY_BY_ID','DATE_CREATE','DATE_MODIFY','SOURCE_ID','SOURCE_DESCRIPTION','LEAD_ID','ADDITIONAL_INFO','LOCATION_ID','ORIGINATOR_ID','ORIGIN_ID','UTM_SOURCE','UTM_MEDIUM','UTM_CAMPAIGN','UTM_CONTENT','UTM_TERM'] + * @param int|null $limit * - * @return Generator + * @return Generator|DealItemResult[] * @throws BaseException */ public function list(array $order, array $filter, array $select, ?int $limit = null): Generator @@ -223,4 +224,25 @@ public function delete(array $dealId): Generator yield $key => new DeletedItemBatchResult($item); } } + + /** + * Update deals + * + * Update elements in array with structure + * element_id => [ // deal id + * 'fields' => [], // deal fields to update + * 'params' => [] + * ] + * + * @param array $entityItems + * + * @return \Generator + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function update(array $entityItems): Generator + { + foreach ($this->batch->updateEntityItems('crm.deal.update', $entityItems) as $key => $item) { + yield $key => new UpdatedItemBatchResult($item); + } + } } \ No newline at end of file diff --git a/src/Services/CRM/Lead/Result/LeadItemResult.php b/src/Services/CRM/Lead/Result/LeadItemResult.php new file mode 100644 index 00000000..ab26d91c --- /dev/null +++ b/src/Services/CRM/Lead/Result/LeadItemResult.php @@ -0,0 +1,81 @@ +getKeyWithUserfieldByFieldName($userfieldName); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Lead/Result/LeadResult.php b/src/Services/CRM/Lead/Result/LeadResult.php new file mode 100644 index 00000000..5fbfcc91 --- /dev/null +++ b/src/Services/CRM/Lead/Result/LeadResult.php @@ -0,0 +1,24 @@ +getCoreResponse()->getResponseData()->getResult()); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Lead/Result/LeadsResult.php b/src/Services/CRM/Lead/Result/LeadsResult.php new file mode 100644 index 00000000..2a2ebef3 --- /dev/null +++ b/src/Services/CRM/Lead/Result/LeadsResult.php @@ -0,0 +1,31 @@ +getCoreResponse()->getResponseData()->getResult() as $item) { + $items[] = new LeadItemResult($item); + } + + return $items; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Lead/Service/Batch.php b/src/Services/CRM/Lead/Service/Batch.php new file mode 100644 index 00000000..934457c5 --- /dev/null +++ b/src/Services/CRM/Lead/Service/Batch.php @@ -0,0 +1,226 @@ +batch = $batch; + $this->log = $log; + } + + /** + * Batch list method for leads + * + * @param array{ + * ID?: string, + * TITLE?: string, + * TYPE_ID?: string, + * CATEGORY_ID?: string, + * STAGE_ID?: string, + * STAGE_SEMANTIC_ID?: string, + * IS_NEW?: string, + * IS_RECURRING?: string, + * IS_RETURN_CUSTOMER?: string, + * IS_REPEATED_APPROACH?: string, + * PROBABILITY?: string, + * CURRENCY_ID?: string, + * OPPORTUNITY?: string, + * IS_MANUAL_OPPORTUNITY?: string, + * TAX_VALUE?: string, + * COMPANY_ID?: string, + * CONTACT_ID?: string, + * CONTACT_IDS?: string, + * QUOTE_ID?: string, + * BEGINDATE?: string, + * CLOSEDATE?: string, + * OPENED?: string, + * CLOSED?: string, + * COMMENTS?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: string, + * LEAD_ID?: string, + * ADDITIONAL_INFO?: string, + * LOCATION_ID?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string, + * } $order + * + * @param array{ + * ID?: int, + * TITLE?: string, + * TYPE_ID?: string, + * CATEGORY_ID?: string, + * STAGE_ID?: string, + * STAGE_SEMANTIC_ID?: string, + * IS_NEW?: string, + * IS_RECURRING?: string, + * IS_RETURN_CUSTOMER?: string, + * IS_REPEATED_APPROACH?: string, + * PROBABILITY?: int, + * CURRENCY_ID?: string, + * OPPORTUNITY?: string, + * IS_MANUAL_OPPORTUNITY?: string, + * TAX_VALUE?: string, + * COMPANY_ID?: string, + * CONTACT_ID?: string, + * CONTACT_IDS?: string, + * QUOTE_ID?: string, + * BEGINDATE?: string, + * CLOSEDATE?: string, + * OPENED?: string, + * CLOSED?: string, + * COMMENTS?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: string, + * LEAD_ID?: string, + * ADDITIONAL_INFO?: string, + * LOCATION_ID?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string, + * } $filter + * @param array $select = ['ID','TITLE','TYPE_ID','CATEGORY_ID','STAGE_ID','STAGE_SEMANTIC_ID','IS_NEW','IS_RECURRING','IS_RETURN_CUSTOMER','IS_REPEATED_APPROACH','PROBABILITY','CURRENCY_ID','OPPORTUNITY','IS_MANUAL_OPPORTUNITY','TAX_VALUE','COMPANY_ID','CONTACT_ID','CONTACT_IDS','QUOTE_ID','BEGINDATE','CLOSEDATE','OPENED','CLOSED','COMMENTS','ASSIGNED_BY_ID','CREATED_BY_ID','MODIFY_BY_ID','DATE_CREATE','DATE_MODIFY','SOURCE_ID','SOURCE_DESCRIPTION','LEAD_ID','ADDITIONAL_INFO','LOCATION_ID','ORIGINATOR_ID','ORIGIN_ID','UTM_SOURCE','UTM_MEDIUM','UTM_CAMPAIGN','UTM_CONTENT','UTM_TERM'] + * @param int|null $limit + * + * @return Generator + * @throws BaseException + */ + public function list(array $order, array $filter, array $select, ?int $limit = null): Generator + { + $this->log->debug( + 'batchList', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'limit' => $limit, + ] + ); + foreach ($this->batch->getTraversableList('crm.lead.list', $order, $filter, $select, $limit) as $key => $value) { + yield $key => new DealItemResult($value); + } + } + + /** + * Batch adding leads + * + * @param array $leads + * + * @return Generator|AddedItemBatchResult[] + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function add(array $leads): Generator + { + $items = []; + foreach ($leads as $lead) { + $items[] = [ + 'fields' => $lead, + ]; + } + foreach ($this->batch->addEntityItems('crm.lead.add', $items) as $key => $item) { + yield $key => new AddedItemBatchResult($item); + } + } + + /** + * Batch delete leads + * + * @param int[] $leadId + * + * @return \Generator|\Bitrix24\SDK\Core\Contracts\DeletedItemResultInterface[] + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function delete(array $leadId): Generator + { + foreach ($this->batch->deleteEntityItems('crm.lead.delete', $leadId) as $key => $item) { + yield $key => new DeletedItemBatchResult($item); + } + } +} \ No newline at end of file diff --git a/src/Services/CRM/Lead/Service/Lead.php b/src/Services/CRM/Lead/Service/Lead.php new file mode 100644 index 00000000..808a5b63 --- /dev/null +++ b/src/Services/CRM/Lead/Service/Lead.php @@ -0,0 +1,357 @@ +batch = $batch; + } + + /** + * add new lead + * + * @link https://training.bitrix24.com/rest_help/crm/leads/crm_lead_add.php + * + * @param array{ + * ID?: int, + * TITLE?: string, + * HONORIFIC?: string, + * NAME?: string, + * SECOND_NAME?: string, + * LAST_NAME?: string, + * BIRTHDATE?: string, + * COMPANY_TITLE?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: string, + * STATUS_ID?: string, + * STATUS_DESCRIPTION?: string, + * STATUS_SEMANTIC_ID?: string, + * POST?: string, + * ADDRESS?: string, + * ADDRESS_2?: string, + * ADDRESS_CITY?: string, + * ADDRESS_POSTAL_CODE?: string, + * ADDRESS_REGION?: string, + * ADDRESS_PROVINCE?: string, + * ADDRESS_COUNTRY?: string, + * ADDRESS_COUNTRY_CODE?: string, + * ADDRESS_LOC_ADDR_ID?: int, + * CURRENCY_ID?: string, + * OPPORTUNITY?: string, + * IS_MANUAL_OPPORTUNITY?: string, + * OPENED?: string, + * COMMENTS?: string, + * HAS_PHONE?: string, + * HAS_EMAIL?: string, + * HAS_IMOL?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * MOVED_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * MOVED_TIME?: string, + * COMPANY_ID?: string, + * CONTACT_ID?: string, + * CONTACT_IDS?: string, + * IS_RETURN_CUSTOMER?: string, + * DATE_CLOSED?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string, + * PHONE?: string, + * EMAIL?: string, + * WEB?: string, + * IM?: string, + * LINK?: string + * } $fields + * + * @param array{ + * REGISTER_SONET_EVENT?: string + * } $params + * + * @return AddedItemResult + * @throws BaseException + * @throws TransportException + */ + public function add(array $fields, array $params = []): AddedItemResult + { + return new AddedItemResult( + $this->core->call( + 'crm.lead.add', + [ + 'fields' => $fields, + 'params' => $params, + ] + ) + ); + } + + /** + * Deletes the specified lead and all the associated objects. + * + * @link https://training.bitrix24.com/rest_help/crm/leads/crm_lead_delete.php + * + * @param int $id + * + * @return DeletedItemResult + * @throws BaseException + * @throws TransportException + */ + public function delete(int $id): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call( + 'crm.lead.delete', + [ + 'id' => $id, + ] + ) + ); + } + + /** + * Returns the description of the lead fields, including user fields. + * + * @link https://training.bitrix24.com/rest_help/crm/leads/crm_lead_fields.php + * + * @return FieldsResult + * @throws BaseException + * @throws TransportException + */ + public function fields(): FieldsResult + { + return new FieldsResult($this->core->call('crm.lead.fields')); + } + + /** + * Returns a lead by the lead ID. + * + * @link https://training.bitrix24.com/rest_help/crm/leads/crm_lead_get.php + * + * @param int $id + * + * @return LeadResult + * @throws BaseException + * @throws TransportException + */ + public function get(int $id): LeadResult + { + return new LeadResult($this->core->call('crm.lead.get', ['id' => $id])); + } + + /** + * Get list of lead items. + * + * @link https://training.bitrix24.com/rest_help/crm/leads/crm_lead_list.php + * + * @param array $order - order of lead items + * @param array $filter - filter array + * @param array $select = ['ID','TITLE','HONORIFIC','NAME','SECOND_NAME','LAST_NAME','BIRTHDATE','COMPANY_TITLE','SOURCE_ID','SOURCE_DESCRIPTION','STATUS_ID','STATUS_DESCRIPTION','STATUS_SEMANTIC_ID','POST','ADDRESS','ADDRESS_2','ADDRESS_CITY','ADDRESS_POSTAL_CODE','ADDRESS_REGION','ADDRESS_PROVINCE','ADDRESS_COUNTRY','ADDRESS_COUNTRY_CODE','ADDRESS_LOC_ADDR_ID','CURRENCY_ID','OPPORTUNITY','IS_MANUAL_OPPORTUNITY','OPENED','COMMENTS','HAS_PHONE','HAS_EMAIL','HAS_IMOL','ASSIGNED_BY_ID','CREATED_BY_ID','MODIFY_BY_ID','MOVED_BY_ID','DATE_CREATE','DATE_MODIFY','MOVED_TIME','COMPANY_ID','CONTACT_ID','CONTACT_IDS','IS_RETURN_CUSTOMER','DATE_CLOSED','ORIGINATOR_ID','ORIGIN_ID','UTM_SOURCE','UTM_MEDIUM','UTM_CAMPAIGN','UTM_CONTENT','UTM_TERM','PHONE','EMAIL','WEB','IM','LINK'] + * @param integer $startItem - entity number to start from (usually returned in 'next' field of previous 'crm.lead.list' API call) + * + * @throws BaseException + * @throws TransportException + * @return LeadsResult + */ + public function list(array $order, array $filter, array $select, int $startItem = 0): LeadsResult + { + return new LeadsResult( + $this->core->call( + 'crm.lead.list', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $startItem, + ] + ) + ); + } + + /** + * Updates the specified (existing) lead. + * + * @link https://training.bitrix24.com/rest_help/crm/leads/crm_lead_update.php + * + * @param int $id + * @param array{ + * ID?: int, + * TITLE?: string, + * HONORIFIC?: string, + * NAME?: string, + * SECOND_NAME?: string, + * LAST_NAME?: string, + * BIRTHDATE?: string, + * COMPANY_TITLE?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: string, + * STATUS_ID?: string, + * STATUS_DESCRIPTION?: string, + * STATUS_SEMANTIC_ID?: string, + * POST?: string, + * ADDRESS?: string, + * ADDRESS_2?: string, + * ADDRESS_CITY?: string, + * ADDRESS_POSTAL_CODE?: string, + * ADDRESS_REGION?: string, + * ADDRESS_PROVINCE?: string, + * ADDRESS_COUNTRY?: string, + * ADDRESS_COUNTRY_CODE?: string, + * ADDRESS_LOC_ADDR_ID?: int, + * CURRENCY_ID?: string, + * OPPORTUNITY?: string, + * IS_MANUAL_OPPORTUNITY?: string, + * OPENED?: string, + * COMMENTS?: string, + * HAS_PHONE?: string, + * HAS_EMAIL?: string, + * HAS_IMOL?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * MOVED_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * MOVED_TIME?: string, + * COMPANY_ID?: string, + * CONTACT_ID?: string, + * CONTACT_IDS?: string, + * IS_RETURN_CUSTOMER?: string, + * DATE_CLOSED?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string, + * PHONE?: string, + * EMAIL?: string, + * WEB?: string, + * IM?: string, + * LINK?: string + * } $fields + * + * @param array{ + * REGISTER_SONET_EVENT?: string + * } $params + * + * @return UpdatedItemResult + * @throws BaseException + * @throws TransportException + */ + public function update(int $id, array $fields, array $params = []): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call( + 'crm.lead.update', + [ + 'id' => $id, + 'fields' => $fields, + 'params' => $params, + ] + ) + ); + } + + /** + * Count leads by filter + * + * @param array{ + * ID?: int, + * TITLE?: string, + * HONORIFIC?: string, + * NAME?: string, + * SECOND_NAME?: string, + * LAST_NAME?: string, + * BIRTHDATE?: string, + * COMPANY_TITLE?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: string, + * STATUS_ID?: string, + * STATUS_DESCRIPTION?: string, + * STATUS_SEMANTIC_ID?: string, + * POST?: string, + * ADDRESS?: string, + * ADDRESS_2?: string, + * ADDRESS_CITY?: string, + * ADDRESS_POSTAL_CODE?: string, + * ADDRESS_REGION?: string, + * ADDRESS_PROVINCE?: string, + * ADDRESS_COUNTRY?: string, + * ADDRESS_COUNTRY_CODE?: string, + * ADDRESS_LOC_ADDR_ID?: int, + * CURRENCY_ID?: string, + * OPPORTUNITY?: string, + * IS_MANUAL_OPPORTUNITY?: string, + * OPENED?: string, + * COMMENTS?: string, + * HAS_PHONE?: string, + * HAS_EMAIL?: string, + * HAS_IMOL?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * MOVED_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * MOVED_TIME?: string, + * COMPANY_ID?: string, + * CONTACT_ID?: string, + * CONTACT_IDS?: string, + * IS_RETURN_CUSTOMER?: string, + * DATE_CLOSED?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string, + * PHONE?: string, + * EMAIL?: string, + * WEB?: string, + * IM?: string, + * LINK?: string + * } $filter + * + * @return int + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function countByFilter(array $filter = []): int + { + return $this->list([], $filter, ['ID'], 1)->getCoreResponse()->getResponseData()->getPagination()->getTotal(); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Product/Result/ProductResult.php b/src/Services/CRM/Product/Result/ProductResult.php index 0feea5f6..07ba6828 100644 --- a/src/Services/CRM/Product/Result/ProductResult.php +++ b/src/Services/CRM/Product/Result/ProductResult.php @@ -11,6 +11,6 @@ class ProductResult extends AbstractResult { public function product(): ProductItemResult { - return new ProductItemResult($this->getCoreResponse()->getResponseData()->getResult()->getResultData()); + return new ProductItemResult($this->getCoreResponse()->getResponseData()->getResult()); } } \ No newline at end of file diff --git a/src/Services/CRM/Product/Result/ProductsResult.php b/src/Services/CRM/Product/Result/ProductsResult.php index a3814d85..dd8caf80 100644 --- a/src/Services/CRM/Product/Result/ProductsResult.php +++ b/src/Services/CRM/Product/Result/ProductsResult.php @@ -22,7 +22,7 @@ class ProductsResult extends AbstractResult public function getProducts(): array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { $res[] = new ProductItemResult($item); } diff --git a/src/Services/CRM/Settings/Result/SettingsModeResult.php b/src/Services/CRM/Settings/Result/SettingsModeResult.php index 63996e6d..25167743 100644 --- a/src/Services/CRM/Settings/Result/SettingsModeResult.php +++ b/src/Services/CRM/Settings/Result/SettingsModeResult.php @@ -15,6 +15,6 @@ class SettingsModeResult extends AbstractResult { public function getModeId(): int { - return $this->getCoreResponse()->getResponseData()->getResult()->getResultData()[0]; + return $this->getCoreResponse()->getResponseData()->getResult()[0]; } } \ No newline at end of file diff --git a/src/Services/CRM/Userfield/Result/UserfieldTypesResult.php b/src/Services/CRM/Userfield/Result/UserfieldTypesResult.php index 212f2a58..507caa83 100644 --- a/src/Services/CRM/Userfield/Result/UserfieldTypesResult.php +++ b/src/Services/CRM/Userfield/Result/UserfieldTypesResult.php @@ -16,7 +16,7 @@ class UserfieldTypesResult extends AbstractResult public function getTypes(): array { $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult()->getResultData() as $item) { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { $res[] = new UserfieldTypeItemResult($item); } diff --git a/src/Services/IMOpenLines/IMOpenLinesServiceBuilder.php b/src/Services/IMOpenLines/IMOpenLinesServiceBuilder.php new file mode 100644 index 00000000..e5e198b8 --- /dev/null +++ b/src/Services/IMOpenLines/IMOpenLinesServiceBuilder.php @@ -0,0 +1,23 @@ +serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Network($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } +} \ No newline at end of file diff --git a/src/Services/IMOpenLines/Result/AddedMessageItemResult.php b/src/Services/IMOpenLines/Result/AddedMessageItemResult.php new file mode 100644 index 00000000..c9683cc1 --- /dev/null +++ b/src/Services/IMOpenLines/Result/AddedMessageItemResult.php @@ -0,0 +1,21 @@ +getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/IMOpenLines/Result/JoinOpenLineResult.php b/src/Services/IMOpenLines/Result/JoinOpenLineResult.php new file mode 100644 index 00000000..516824ef --- /dev/null +++ b/src/Services/IMOpenLines/Result/JoinOpenLineResult.php @@ -0,0 +1,20 @@ +getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/IMOpenLines/Service/Network.php b/src/Services/IMOpenLines/Service/Network.php new file mode 100644 index 00000000..b99fdfca --- /dev/null +++ b/src/Services/IMOpenLines/Service/Network.php @@ -0,0 +1,71 @@ +core->call( + 'imopenlines.network.join', + [ + 'CODE' => $openLineCode, + ] + ) + ); + } + + /** + * Sending Open Channel message to selected user + * + * @param string $openLineCode + * @param int $recipientUserId + * @param string $message + * @param bool $isMakeUrlPreview + * @param array|null $attach + * @param array|null $keyboard + * + * @return AddedMessageItemResult + * @link https://training.bitrix24.com/support/training/course/?COURSE_ID=115&LESSON_ID=25018&LESSON_PATH=9691.9833.20331.25014.25018 + * + */ + public function messageAdd( + string $openLineCode, + int $recipientUserId, + string $message, + bool $isMakeUrlPreview = true, + ?array $attach = null, + ?array $keyboard = null + ): AddedMessageItemResult { + return new AddedMessageItemResult( + $this->core->call( + 'imopenlines.network.message.add', + [ + 'CODE' => $openLineCode, + 'USER_ID' => $recipientUserId, + 'MESSAGE' => $message, + 'URL_PREVIEW' => $isMakeUrlPreview ? 'Y' : 'N', + 'ATTACH' => $attach, + 'KEYBOARD' => $keyboard, + ] + ) + ); + } +} \ No newline at end of file diff --git a/src/Services/Main/MainServiceBuilder.php b/src/Services/Main/MainServiceBuilder.php index 9591f032..ce6f34ce 100644 --- a/src/Services/Main/MainServiceBuilder.php +++ b/src/Services/Main/MainServiceBuilder.php @@ -6,6 +6,7 @@ use Bitrix24\SDK\Services\AbstractServiceBuilder; use Bitrix24\SDK\Services\Main\Service\Main; +use Bitrix24\SDK\Services\Main\Service\Event; /** * Class MainServiceBuilder @@ -25,4 +26,16 @@ public function main(): Main return $this->serviceCache[__METHOD__]; } + + /** + * @return Event + */ + public function event(): Event + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Event($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } } \ No newline at end of file diff --git a/src/Services/Main/Result/ApplicationInfoItemResult.php b/src/Services/Main/Result/ApplicationInfoItemResult.php new file mode 100644 index 00000000..d76bd1fd --- /dev/null +++ b/src/Services/Main/Result/ApplicationInfoItemResult.php @@ -0,0 +1,32 @@ +STATUS !== null ? new ApplicationStatus($this->STATUS) : null; + } +} \ No newline at end of file diff --git a/src/Services/Main/Result/ApplicationInfoResult.php b/src/Services/Main/Result/ApplicationInfoResult.php new file mode 100644 index 00000000..b6c61fca --- /dev/null +++ b/src/Services/Main/Result/ApplicationInfoResult.php @@ -0,0 +1,16 @@ +getCoreResponse()->getResponseData()->getResult()); + } +} \ No newline at end of file diff --git a/src/Services/Main/Result/EventHandlerBindResult.php b/src/Services/Main/Result/EventHandlerBindResult.php new file mode 100644 index 00000000..bf511882 --- /dev/null +++ b/src/Services/Main/Result/EventHandlerBindResult.php @@ -0,0 +1,20 @@ +getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Main/Result/EventHandlerItemResult.php b/src/Services/Main/Result/EventHandlerItemResult.php new file mode 100644 index 00000000..75c0a8c6 --- /dev/null +++ b/src/Services/Main/Result/EventHandlerItemResult.php @@ -0,0 +1,17 @@ +getCoreResponse()->getResponseData()->getResult()['count']; + } +} \ No newline at end of file diff --git a/src/Services/Main/Result/EventHandlersResult.php b/src/Services/Main/Result/EventHandlersResult.php new file mode 100644 index 00000000..7addf375 --- /dev/null +++ b/src/Services/Main/Result/EventHandlersResult.php @@ -0,0 +1,25 @@ +getCoreResponse()->getResponseData()->getResult() as $event) { + $res[] = new EventHandlerItemResult($event); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/Main/Result/EventListResult.php b/src/Services/Main/Result/EventListResult.php new file mode 100644 index 00000000..695cf217 --- /dev/null +++ b/src/Services/Main/Result/EventListResult.php @@ -0,0 +1,20 @@ +getCoreResponse()->getResponseData()->getResult(); + } +} \ No newline at end of file diff --git a/src/Services/Main/Result/IsUserAdminResult.php b/src/Services/Main/Result/IsUserAdminResult.php new file mode 100644 index 00000000..1bee191b --- /dev/null +++ b/src/Services/Main/Result/IsUserAdminResult.php @@ -0,0 +1,20 @@ +getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Main/Result/MethodAffordabilityResult.php b/src/Services/Main/Result/MethodAffordabilityResult.php new file mode 100644 index 00000000..ad64373c --- /dev/null +++ b/src/Services/Main/Result/MethodAffordabilityResult.php @@ -0,0 +1,29 @@ +getCoreResponse()->getResponseData()->getResult()['isExisting']; + } + + /** + * @return bool + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function isAvailable(): bool + { + return $this->getCoreResponse()->getResponseData()->getResult()['isAvailable']; + } +} \ No newline at end of file diff --git a/src/Services/Main/Result/ServerTimeResult.php b/src/Services/Main/Result/ServerTimeResult.php new file mode 100644 index 00000000..45d11321 --- /dev/null +++ b/src/Services/Main/Result/ServerTimeResult.php @@ -0,0 +1,21 @@ +getCoreResponse()->getResponseData()->getResult()[0]); + } +} \ No newline at end of file diff --git a/src/Services/Main/Result/UserProfileItemResult.php b/src/Services/Main/Result/UserProfileItemResult.php new file mode 100644 index 00000000..d5bc4938 --- /dev/null +++ b/src/Services/Main/Result/UserProfileItemResult.php @@ -0,0 +1,45 @@ +data[$offset] !== '' && $this->data[$offset] !== null) { + return (int)$this->data[$offset]; + } + return null; + default: + return parent::__get($offset); + } + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public function getStatus(): ?ApplicationStatus + { + return $this->STATUS !== null ? new ApplicationStatus($this->STATUS) : null; + } +} \ No newline at end of file diff --git a/src/Services/Main/Result/UserProfileResult.php b/src/Services/Main/Result/UserProfileResult.php new file mode 100644 index 00000000..2885e435 --- /dev/null +++ b/src/Services/Main/Result/UserProfileResult.php @@ -0,0 +1,16 @@ +getCoreResponse()->getResponseData()->getResult()); + } +} \ No newline at end of file diff --git a/src/Services/Main/Service/Event.php b/src/Services/Main/Service/Event.php new file mode 100644 index 00000000..cf5d2fa6 --- /dev/null +++ b/src/Services/Main/Service/Event.php @@ -0,0 +1,119 @@ +core->call( + 'events', + $scopeCode !== null ? ['scope' => (new Scope([$scopeCode]))->getScopeCodes()[0]] : [] + ) + ); + } + + /** + * Installs a new event handler. + * + * @param string $eventCode + * @param string $handlerUrl + * @param int|null $userId + * @param array|null $options + * + * @return \Bitrix24\SDK\Services\Main\Result\EventHandlerBindResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/general/events_method/event_bind.php + */ + public function bind(string $eventCode, string $handlerUrl, ?int $userId = null, ?array $options = null): EventHandlerBindResult + { + $params = [ + 'event' => $eventCode, + 'handler' => $handlerUrl, + 'event_type ' => 'online', + ]; + if ($userId !== null) { + $params['auth_type'] = $userId; + } + if (is_array($options)) { + $params = array_merge($params, $options); + } + + return new EventHandlerBindResult($this->core->call('event.bind', $params)); + } + + /** + * Uninstalls a previously installed event handler. + * + * @param string $eventCode + * @param string $handlerUrl + * @param int|null $userId + * + * @return \Bitrix24\SDK\Services\Main\Result\EventHandlerUnbindResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/general/events_method/event_unbind.php + */ + public function unbind(string $eventCode, string $handlerUrl, ?int $userId = null): EventHandlerUnbindResult + { + $params = [ + 'event' => $eventCode, + 'handler' => $handlerUrl, + 'event_type ' => 'online', + ]; + if ($userId !== null) { + $params['auth_type'] = $userId; + } + + return new EventHandlerUnbindResult($this->core->call('event.unbind', $params)); + } + + /** + * @param array $payload + * + * @return \Bitrix24\SDK\Core\Response\Response + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/rest_sum/test_handler.php + */ + public function test(array $payload = []): Response + { + return $this->core->call('event.test', $payload); + } + + /** + * Obtaining a list of registered event handlers. + * + * @return \Bitrix24\SDK\Services\Main\Result\EventHandlersResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/general/events_method/event_get.php + */ + public function get(): EventHandlersResult + { + return new EventHandlersResult($this->core->call('event.get')); + } +} \ No newline at end of file diff --git a/src/Services/Main/Service/Main.php b/src/Services/Main/Service/Main.php index e49f8bf3..7d4bd720 100644 --- a/src/Services/Main/Service/Main.php +++ b/src/Services/Main/Service/Main.php @@ -8,6 +8,11 @@ use Bitrix24\SDK\Core\Exceptions\TransportException; use Bitrix24\SDK\Core\Response\Response; use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Main\Result\ApplicationInfoResult; +use Bitrix24\SDK\Services\Main\Result\IsUserAdminResult; +use Bitrix24\SDK\Services\Main\Result\MethodAffordabilityResult; +use Bitrix24\SDK\Services\Main\Result\ServerTimeResult; +use Bitrix24\SDK\Services\Main\Result\UserProfileResult; /** * Class Main @@ -17,137 +22,177 @@ class Main extends AbstractService { /** - * @return Response - * @throws BaseException - * @throws TransportException + * Method returns current server time in the format YYYY-MM-DDThh:mm:ss±hh:mm. + * + * @link https://training.bitrix24.com/rest_help/general/server_time.php + * @return \Bitrix24\SDK\Services\Main\Result\ServerTimeResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException */ - public function getCurrentScope(): Response + public function getServerTime(): ServerTimeResult + { + return new ServerTimeResult($this->core->call('server.time')); + } + + /** + * Allows to return basic Information about the current user without any scopes, in contrast to user.current. + * + * @link https://training.bitrix24.com/rest_help/general/profile.php + * @return \Bitrix24\SDK\Services\Main\Result\UserProfileResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function getCurrentUserProfile(): UserProfileResult { - $this->log->debug('getCurrentScope.start'); + return new UserProfileResult($this->core->call('profile')); + } - $result = $this->core->call('scope'); + /** + * Returns access permission names. + * + * @param array $accessList + * + * @return \Bitrix24\SDK\Core\Response\Response + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/general/access_name.php + */ + public function getAccessName(array $accessList): Response + { + return $this->core->call('access.name', [ + 'ACCESS' => $accessList, + ]); + } - $this->log->debug('getCurrentScope.finish'); + /** + * Checks if the current user has at least one permission of those specified by the ACCESS parameter. + * + * @param array $accessToCheck + * + * @return \Bitrix24\SDK\Core\Response\Response + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/general/user_access.php + */ + public function checkUserAccess(array $accessToCheck): Response + { + return $this->core->call('user.access', [ + 'ACCESS' => $accessToCheck, + ]); + } - return $result; + /** + * Method returns 2 parameters - isExisting and isAvailable + * + * @param string $methodName + * + * @return \Bitrix24\SDK\Services\Main\Result\MethodAffordabilityResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/general/method_get.php + */ + public function getMethodAffordability(string $methodName): MethodAffordabilityResult + { + return new MethodAffordabilityResult( + $this->core->call('method.get', [ + 'name' => $methodName, + ]) + ); } /** + * It will return permissions available to the current application. + * * @return Response * @throws BaseException * @throws TransportException + * @link https://training.bitrix24.com/rest_help/general/scope.php */ - public function getAvailableScope(): Response + public function getCurrentScope(): Response { - $this->log->debug('getAvailableScope.start'); - - $result = $this->core->call('scope', ['full' => true]); - - $this->log->debug('getAvailableScope.finish'); - - return $result; + return $this->core->call('scope'); } /** + * Method will return a list of all possible permissions. + * * @return Response * @throws BaseException * @throws TransportException + * @link https://training.bitrix24.com/rest_help/general/scope.php */ - public function getAvailableMethods(): Response + public function getAvailableScope(): Response { - $this->log->debug('getAvailableMethods.start'); - - $result = $this->core->call('methods', []); - - $this->log->debug('getAvailableMethods.finish'); - - return $result; + return $this->core->call('scope', ['full' => true]); } /** + * Returns the methods available to the current application + * * @return Response * @throws BaseException * @throws TransportException + * @deprecated use method.get + * @link https://training.bitrix24.com/rest_help/general/methods.php */ - public function getAllMethods(): Response + public function getAvailableMethods(): Response { - $this->log->debug('getAllMethods.start'); - - $result = $this->core->call('methods', ['full' => true]); - - $this->log->debug('getAllMethods.finish'); - - return $result; + return $this->core->call('methods', []); } /** - * @param string $scope + * Returns the methods available * * @return Response * @throws BaseException * @throws TransportException + * @deprecated use method.get + * @link https://training.bitrix24.com/rest_help/general/methods.php */ - public function getMethodsByScope(string $scope): Response + public function getAllMethods(): Response { - $this->log->debug( - 'getMethodsByScope.start', - [ - 'scope' => $scope, - ] - ); - - $result = $this->core->call('methods', ['scope' => $scope]); - - $this->log->debug('getMethodsByScope.finish'); - - return $result; + return $this->core->call('methods', ['full' => true]); } /** + * Returns the methods available to the current application + * + * @param string $scope + * * @return Response * @throws BaseException * @throws TransportException + * @deprecated use method.get + * @link https://training.bitrix24.com/rest_help/general/methods.php */ - public function getApplicationInfo(): Response + public function getMethodsByScope(string $scope): Response { - $this->log->debug('getApplicationInfo.start'); - - $result = $this->core->call('app.info'); - - $this->log->debug('getApplicationInfo.finish'); - - return $result; + return $this->core->call('methods', ['scope' => $scope]); } /** - * @return Response + * Displays application information. The method supports secure calling convention. + * + * @return ApplicationInfoResult * @throws BaseException * @throws TransportException + * @link https://training.bitrix24.com/rest_help/general/app_info.php */ - public function isCurrentUserHasAdminRights(): Response + public function getApplicationInfo(): ApplicationInfoResult { - $this->log->debug('isCurrentUserHasAdminRights.start'); - - $result = $this->core->call('user.admin'); - - $this->log->debug('isCurrentUserHasAdminRights.finish'); - - return $result; + return new ApplicationInfoResult($this->core->call('app.info')); } /** - * @return Response + * Checks if a current user has permissions to manage application parameters. + * + * @return IsUserAdminResult * @throws BaseException * @throws TransportException + * @link https://training.bitrix24.com/rest_help/general/user_admin.php */ - public function getUserProfile(): Response + public function isCurrentUserHasAdminRights(): IsUserAdminResult { - $this->log->debug('getUserProfile.start'); - - $result = $this->core->call('profile'); - - $this->log->debug('getUserProfile.finish'); - - return $result; + return new IsUserAdminResult($this->core->call('user.admin')); } } \ No newline at end of file diff --git a/src/Services/Placement/PlacementServiceBuilder.php b/src/Services/Placement/PlacementServiceBuilder.php new file mode 100644 index 00000000..22b838be --- /dev/null +++ b/src/Services/Placement/PlacementServiceBuilder.php @@ -0,0 +1,36 @@ +serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Placement($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * @return \Bitrix24\SDK\Services\Placement\Service\UserFieldType + */ + public function userfieldtype(): UserFieldType + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new UserFieldType($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } +} \ No newline at end of file diff --git a/src/Services/Placement/Result/DeleteUserTypeResult.php b/src/Services/Placement/Result/DeleteUserTypeResult.php new file mode 100644 index 00000000..66cfb1ce --- /dev/null +++ b/src/Services/Placement/Result/DeleteUserTypeResult.php @@ -0,0 +1,20 @@ +getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Placement/Result/PlacementBindResult.php b/src/Services/Placement/Result/PlacementBindResult.php new file mode 100644 index 00000000..4dfa0ddd --- /dev/null +++ b/src/Services/Placement/Result/PlacementBindResult.php @@ -0,0 +1,20 @@ +getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Placement/Result/PlacementLocationCodesResult.php b/src/Services/Placement/Result/PlacementLocationCodesResult.php new file mode 100644 index 00000000..0804042b --- /dev/null +++ b/src/Services/Placement/Result/PlacementLocationCodesResult.php @@ -0,0 +1,19 @@ +getCoreResponse()->getResponseData()->getResult(); + } +} \ No newline at end of file diff --git a/src/Services/Placement/Result/PlacementLocationItemResult.php b/src/Services/Placement/Result/PlacementLocationItemResult.php new file mode 100644 index 00000000..4b3b829b --- /dev/null +++ b/src/Services/Placement/Result/PlacementLocationItemResult.php @@ -0,0 +1,19 @@ +getCoreResponse()->getResponseData()->getResult()['count']; + } +} \ No newline at end of file diff --git a/src/Services/Placement/Result/PlacementsLocationInformationResult.php b/src/Services/Placement/Result/PlacementsLocationInformationResult.php new file mode 100644 index 00000000..328f3ae4 --- /dev/null +++ b/src/Services/Placement/Result/PlacementsLocationInformationResult.php @@ -0,0 +1,25 @@ +getCoreResponse()->getResponseData()->getResult() as $item) { + $res[] = new PlacementLocationItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/Placement/Result/RegisterUserTypeResult.php b/src/Services/Placement/Result/RegisterUserTypeResult.php new file mode 100644 index 00000000..2a0c6baf --- /dev/null +++ b/src/Services/Placement/Result/RegisterUserTypeResult.php @@ -0,0 +1,20 @@ +getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Placement/Result/UserFieldTypeItemResult.php b/src/Services/Placement/Result/UserFieldTypeItemResult.php new file mode 100644 index 00000000..4ed69497 --- /dev/null +++ b/src/Services/Placement/Result/UserFieldTypeItemResult.php @@ -0,0 +1,17 @@ +getCoreResponse()->getResponseData()->getResult() as $item) { + $res[] = new UserFieldTypeItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/Placement/Service/Placement.php b/src/Services/Placement/Service/Placement.php new file mode 100644 index 00000000..f27fd63f --- /dev/null +++ b/src/Services/Placement/Service/Placement.php @@ -0,0 +1,96 @@ +core->call( + 'placement.bind', + [ + 'PLACEMENT' => $placementCode, + 'HANDLER' => $handlerUrl, + 'LANG_ALL' => $lang, + ] + ) + ); + } + + /** + * Deletes the registered embedding location handler. Shall be executed with the available account administrative privileges. + * + * @param string $placementCode + * @param string|null $handlerUrl + * + * @return \Bitrix24\SDK\Services\Placement\Result\PlacementUnbindResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/application_embedding/metods/placement_unbind.php + */ + public function unbind(string $placementCode, ?string $handlerUrl = null): PlacementUnbindResult + { + return new PlacementUnbindResult( + $this->core->call( + 'placement.unbind', + [ + 'PLACEMENT' => $placementCode, + 'HANDLER' => $handlerUrl, + ] + ) + ); + } + + /** + * This method is used to retrieve the list of embedding locations, available to the application. + * + * @param string|null $applicationScopeCode + * + * @return PlacementLocationCodesResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/application_embedding/metods/placement_list.php + */ + public function list(?string $applicationScopeCode = null): PlacementLocationCodesResult + { + return new PlacementLocationCodesResult( + $this->core->call('placement.list', [ + 'SCOPE' => $applicationScopeCode, + ]) + ); + } + + /** + * This method is used to retrieve the list of registered handlers for embedding locations. + * + * @return PlacementsLocationInformationResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/application_embedding/metods/placement_get.php + */ + public function get(): PlacementsLocationInformationResult + { + return new PlacementsLocationInformationResult($this->core->call('placement.get')); + } +} \ No newline at end of file diff --git a/src/Services/Placement/Service/PlacementLocationCode.php b/src/Services/Placement/Service/PlacementLocationCode.php new file mode 100644 index 00000000..6602e5bf --- /dev/null +++ b/src/Services/Placement/Service/PlacementLocationCode.php @@ -0,0 +1,147 @@ +core->call( + 'userfieldtype.add', + [ + 'USER_TYPE_ID' => $userTypeId, + 'HANDLER' => $handlerUrl, + 'TITLE' => $title, + 'DESCRIPTION' => $description, + ] + ) + ); + } + + /** + * Retrieves list of user field types, registrered by the application. List method. Results in the list of field types with page-by-page navigation. + * + * @return UserFieldTypesResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/application_embedding/user_field/userfieldtype_list.php + */ + public function list(): UserFieldTypesResult + { + return new UserFieldTypesResult( + $this->core->call('userfieldtype.list') + ); + } + + /** + * Modifies settings of user field types, registered by the application. This method returns true or an error with description. + * + * @param string $userTypeId Inline code of the type. Required parameter. a-z0-9 + * @param string $handlerUrl Address of user type handler. Required parameter. Shall be in the same domain as the main application address. + * @param string $title Type text name. Will be displayed in the admin interface of user field settings. + * @param string $description Type text description. Will be displayed in the admin interface of user field settings. + * + * @return \Bitrix24\SDK\Services\Placement\Result\RegisterUserTypeResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/application_embedding/user_field/userfieldtype_update.php + */ + public function update(string $userTypeId, string $handlerUrl, string $title, string $description): RegisterUserTypeResult + { + return new RegisterUserTypeResult( + $this->core->call( + 'userfieldtype.update', + [ + 'USER_TYPE_ID' => $userTypeId, + 'HANDLER' => $handlerUrl, + 'TITLE' => $title, + 'DESCRIPTION' => $description, + ] + ) + ); + } + + /** + * Deletes user field type, registered by the application. This method returns true or an error with description. + * + * @param string $userTypeId Inline code of the type. Required parameter. a-z0-9 + * + * @return \Bitrix24\SDK\Services\Placement\Result\DeleteUserTypeResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/application_embedding/user_field/userfieldtype_delete.php + */ + public function delete(string $userTypeId): DeleteUserTypeResult + { + return new DeleteUserTypeResult( + $this->core->call( + 'userfieldtype.delete', + [ + 'USER_TYPE_ID' => $userTypeId, + ] + ) + ); + } +} \ No newline at end of file diff --git a/src/Services/ServiceBuilder.php b/src/Services/ServiceBuilder.php index fa8a51a9..ecc0cac0 100644 --- a/src/Services/ServiceBuilder.php +++ b/src/Services/ServiceBuilder.php @@ -6,7 +6,11 @@ use Bitrix24\SDK\Services\CRM\CRMServiceBuilder; use Bitrix24\SDK\Services\IM\IMServiceBuilder; +use Bitrix24\SDK\Services\IMOpenLines\IMOpenLinesServiceBuilder; use Bitrix24\SDK\Services\Main\MainServiceBuilder; +use Bitrix24\SDK\Services\Telephony\TelephonyServiceBuilder; +use Bitrix24\SDK\Services\UserConsent\UserConsentServiceBuilder; +use Bitrix24\SDK\Services\Placement\PlacementServiceBuilder; /** * Class ServiceBuilder @@ -39,6 +43,18 @@ public function getIMScope(): IMServiceBuilder return $this->serviceCache[__METHOD__]; } + /** + * @return IMOpenLinesServiceBuilder + */ + public function getIMOpenLinesScope(): IMOpenLinesServiceBuilder + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new IMOpenLinesServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + /** * @return MainServiceBuilder */ @@ -50,4 +66,40 @@ public function getMainScope(): MainServiceBuilder return $this->serviceCache[__METHOD__]; } + + /** + * @return \Bitrix24\SDK\Services\UserConsent\UserConsentServiceBuilder + */ + public function getUserConsentScope(): UserConsentServiceBuilder + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new UserConsentServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * @return PlacementServiceBuilder + */ + public function getPlacementScope(): PlacementServiceBuilder + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new PlacementServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * @return TelephonyServiceBuilder + */ + public function getTelephonyScope(): TelephonyServiceBuilder + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new TelephonyServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } } \ No newline at end of file diff --git a/src/Services/Telephony/Common/CallType.php b/src/Services/Telephony/Common/CallType.php new file mode 100644 index 00000000..acc7d8ab --- /dev/null +++ b/src/Services/Telephony/Common/CallType.php @@ -0,0 +1,123 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Telephony\Common; + +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; + +class CallType +{ + private const OUTBOUND_CALL = 1; + private const INBOUND_CALL = 2; + private const INBOUND_CALL_WITH_REDIRECTION = 3; + private const CALLBACK = 4; + private int $code; + + /** + * @param int $typeCode + * + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + + private function __construct(int $typeCode) + { + switch ($typeCode) { + case $this::INBOUND_CALL: + case $this::OUTBOUND_CALL: + case $this::INBOUND_CALL_WITH_REDIRECTION: + case $this::CALLBACK: + $this->code = $typeCode; + break; + default: + throw new InvalidArgumentException(sprintf('unknown type call %s', $typeCode)); + } + } + + /** + * @return self + */ + public static function outboundCall(): self + { + return new self(self::OUTBOUND_CALL); + } + + /** + * @return bool + */ + public function isOutboundCall(): bool + { + return $this->code === self::OUTBOUND_CALL; + } + + /** + * @return self + */ + public static function inboundCall(): self + { + return new self(self::INBOUND_CALL); + } + + /** + * @return bool + */ + public function isInboundCall(): bool + { + return $this->code === self::INBOUND_CALL; + } + + /** + * @return self + */ + public static function inboundCallWithRedirection(): self + { + return new self(self::INBOUND_CALL_WITH_REDIRECTION); + } + + /** + * @return bool + */ + public function isInboundCallWithRedirection(): bool + { + return $this->code === self::INBOUND_CALL_WITH_REDIRECTION; + } + + /** + * @return self + */ + public static function callback(): self + { + return new self(self::CALLBACK); + } + + /** + * @return bool + */ + public function isCallback(): bool + { + return $this->code === self::CALLBACK; + } + + public function __toString(): string + { + return (string)$this->code; + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public static function initByTypeCode(int $callTypeCode): self + { + return new self($callTypeCode); + } +} + diff --git a/src/Services/Telephony/Common/CrmEntityType.php b/src/Services/Telephony/Common/CrmEntityType.php new file mode 100644 index 00000000..99d280a4 --- /dev/null +++ b/src/Services/Telephony/Common/CrmEntityType.php @@ -0,0 +1,106 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Telephony\Common; + +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; + +class CrmEntityType +{ + private const CONTACT = 'CONTACT'; + private const COMPANY = 'COMPANY'; + private const LEAD = 'LEAD'; + private string $code; + + /** + * @param string $typeCode + * + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + private function __construct(string $typeCode) + { + switch ($typeCode) { + case $this::COMPANY: + case $this::CONTACT: + case $this::LEAD: + $this->code = $typeCode; + break; + default: + throw new InvalidArgumentException(sprintf('unknown crm entity type code %s', $typeCode)); + } + } + + /** + * @return self + */ + public static function contact(): self + { + return new self(self::CONTACT); + } + + /** + * @return bool + */ + public function isContact(): bool + { + return $this->code === $this::CONTACT; + } + + /** + * @return self + */ + public static function company(): self + { + return new self(self::COMPANY); + } + + /** + * @return bool + */ + public function isCompany(): bool + { + return $this->code === $this::COMPANY; + } + + /** + * @return self + */ + public static function lead(): self + { + return new self(self::LEAD); + } + + /** + * @return bool + */ + public function isLead(): bool + { + return $this->code === $this::LEAD; + } + + /** + * @return string + */ + public function __toString(): string + { + return $this->code; + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public static function initByCode(string $entityTypeCode): self + { + return new self($entityTypeCode); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Common/StatusSipCodeInterface.php b/src/Services/Telephony/Common/StatusSipCodeInterface.php new file mode 100644 index 00000000..f3e9a0c7 --- /dev/null +++ b/src/Services/Telephony/Common/StatusSipCodeInterface.php @@ -0,0 +1,100 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Telephony\Common; + +interface StatusSipCodeInterface +{ + //Provisional Responses + public const STATUS_RINGING = 180; + public const STATUS_CALL_IS_BEING_FORWARDED = 181; + public const STATUS_QUEUED = 182; + public const STATUS_SESSION_PROGRESS = 183; + public const STATUS_EARLY_DIALOG_TERMINATED = 199; + //Successful Responses + public const STATUS_OK = 200; + public const STATUS_ACCEPTED = 202; + public const STATUS_NO_NOTIFICATION = 204; + //Redirection Responses + public const STATUS_MULTIPIE_CHOICES = 300; + public const STATUS_MOVED_PERMANENTLY = 301; + public const STATUS_MOVED_TEMPORARILY = 302; + public const STATUS_USE_PROXY = 305; + public const STATUS_ALTERNATIVE_SERVICE = 380; + //Client Failure Responses + public const STATUS_BAD_REQUEST = 400; + public const STATUS_UNAUTHORIZED = 401; + public const STATUS_PAYMENT_REQUIRED = 402; + public const STATUS_FORBIDDEN = 403; + public const STATUS_NOT_FOUND = 404; + public const STATUS_METHOD_NOT_ALLOWED = 405; + public const STATUS_NOT_ACCEPTABLE = 406; + public const STATUS_PROXY_AUTHENTICATION_REQUIRED = 407; + public const STATUS_REQUEST_TIMEOUT = 408; + public const STATUS_C0NFLICT = 409; + public const STATUS_GONE = 410; + public const STATUS_LENGTH_REQUIRED = 411; + public const STATUS_CONDITIONAL_REQUEST_FAILED = 412; + public const STATUS_REQUEST_ENTITY_TOO_LARGE = 413; + public const STATUS_REQUEST_URI_TOO_LONG = 414; + public const STATUS_UNSUPPORTED_MEDIA_TYPE = 415; + public const STATUS_UNSUPPORTED_URI_SCHEME = 416; + public const STATUS_UNKNOWN_RESOURCE_PRIORITY = 417; + public const STATUS_BAD_EXTENSION = 420; + public const STATUS_EXTENSION_REQUIRED = 421; + public const STATUS_SESSION_INTERVAL_TOO_SMALL = 422; + public const STATUS_INTERVAL_TOO_BRIED = 423; + public const STATUS_BAD_LOCATION_INFORMATION = 424; + public const STATUS_BAD_ALERT_MESSAGE = 425; + public const STATUS_USE_IDENTITY_HEADER = 428; + public const STATUS_PROVIDE_REFERRER_IDENTITY = 429; + public const STATUS_FLOW_FAILED = 430; + public const STATUS_ANONYMITY_DISALLOWED = 433; + public const STATUS_BAD_IDENTITY_INFO = 436; + public const STATUS_UNSUPPORTED_CERTIFICATE = 437; + public const STATUS_INVALID_IDENTITY_HEADER = 438; + public const STATUS_FIRST_HOP_LACKS_OUTBOUND_SUPPORT = 439; + public const STATUS_MAX_BREADTH_EXCEEDED = 440; + public const STATUS_BAD_INFO_PACKAGE = 469; + public const STATUS_CONSENT_NEEDED = 470; + public const STATUS_TEMPORARILY_UNAVAILABLE = 480; + public const STATUS_CALL_OR_TRANSACTION_DOES_NOT_EXIST = 481; + public const STATUS_LOOP_DETECTED = 482; + public const STATUS_TOO_MANY_HOPS = 483; + public const STATUS_ADDRESS_INCOMPLETE = 484; + public const STATUS_AMBIGUOUS = 485; + public const STATUS_BUSY_HERE = 486; + public const STATUS_REQUEST_TERMINATED = 487; + public const STATUS_NOT_ACCEPTABLE_HERE = 488; + public const STATUS_BAD_EVENT = 489; + public const STATUS_REQUEST_PENDING = 491; + public const STATUS_UNDECIPHERABLE = 493; + public const STATUS_SECURITY_AGREEMENT_REQUIRED = 494; + //Server Failure Responses + public const STATUS_INTERNAL_SERVER_ERROR = 500; + public const STATUS_NOT_IMPLEMENTED = 501; + public const STATUS_BAD_GATEWAY = 502; + public const STATUS_SERVICE_UNAVAILABLE = 503; + public const STATUS_SERVER_TIME_OUT = 504; + public const STATUS_VERSION_NOT_SUPPORTED = 505; + public const STATUS_MESSAGE_TOO_LARGE = 513; + public const STATUS_PUSH_NOTIFICATION_SERVICE_NOT_SUPPORTED = 555; + public const STATUS_PRECONDITION_FAILURE = 580; + //Global Failure Responses + public const STATUS_BUSY_EVERYWHERE = 600; + public const STATUS_DECLINE = 603; + public const STATUS_DOES_NOT_EXIST_ANYWHERE = 604; + public const STATUS_GLOBAL_NOT_ACCEPTABLE = 606; + public const STATUS_UNWANTED = 607; + public const STATUS_REJECTED = 608; +} \ No newline at end of file diff --git a/src/Services/Telephony/Common/StatusSipRegistrations.php b/src/Services/Telephony/Common/StatusSipRegistrations.php new file mode 100644 index 00000000..6c2984c2 --- /dev/null +++ b/src/Services/Telephony/Common/StatusSipRegistrations.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Telephony\Common; + +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; + +class StatusSipRegistrations +{ + private const SUCCESS = 'success'; + private const ERROR = 'error'; + private const IN_PROGRESS = 'in_progress'; + private const WAIT = 'wait'; + private string $code; + + /** + * @param string $typeSip + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + private function __construct(string $typeSip) + { + switch ($typeSip) { + case $this::SUCCESS: + case $this::ERROR: + case $this::IN_PROGRESS: + case $this::WAIT: + $this->code = $typeSip; + break; + default: + throw new InvalidArgumentException(sprintf('unknown status SIP registrations %s', $typeSip)); + } + } + + /** + * @return self + */ + public static function success(): self + { + return new self(self::SUCCESS); + } + + /** + * @return self + */ + public static function error(): self + { + return new self(self::ERROR); + } + + /** + * @return self + */ + public static function in_progress(): self + { + return new self(self::IN_PROGRESS); + } + + /** + * @return self + */ + public static function wait(): self + { + return new self(self::WAIT); + } + + /** + * @return string + */ + public function __toString(): string + { + return $this->code; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Common/TypeAtc.php b/src/Services/Telephony/Common/TypeAtc.php new file mode 100644 index 00000000..af0ad7bb --- /dev/null +++ b/src/Services/Telephony/Common/TypeAtc.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Telephony\Common; + +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; + +class TypeAtc +{ + private const CLOUD = 'cloud'; + private const OFFICE = 'office'; + private string $code; + + /** + * @param string $typeAtc + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + private function __construct(string $typeAtc) + { + switch ($typeAtc) { + case $this::CLOUD: + case $this::OFFICE: + $this->code = $typeAtc; + break; + default: + throw new InvalidArgumentException(sprintf('unknown type ATC %s', $typeAtc)); + } + } + + /** + * @return self + */ + public static function cloud(): self + { + return new self(self::CLOUD); + } + + /** + * @return self + */ + public static function office(): self + { + return new self(self::OFFICE); + } + + /** + * @return string + */ + public function __toString(): string + { + return $this->code; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/OnExternalCallBackStart.php b/src/Services/Telephony/Requests/Events/OnExternalCallBackStart.php new file mode 100644 index 00000000..7582e152 --- /dev/null +++ b/src/Services/Telephony/Requests/Events/OnExternalCallBackStart.php @@ -0,0 +1,60 @@ +eventPayload['data']['PHONE_NUMBER']; + } + + /** + * @return string Text to be voiced over to a user during initiated call (). + */ + public function getText(): string + { + return $this->eventPayload['data']['TEXT']; + } + + /** + * @return string Voice ID to be used for text voiceover (via form settings). To get a voice IDs list, see voximplant.tts.voices.get. + */ + public function getVoiceId(): string + { + return $this->eventPayload['data']['VOICE']; + } + + /** + * @return \Bitrix24\SDK\Services\Telephony\Common\CrmEntityType + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public function getCrmEntityType(): CrmEntityType + { + return CrmEntityType::initByCode($this->eventPayload['data']['CRM_ENTITY_TYPE']); + } + + /** + * @return int CRM entity ID with type specified in CRM_ENTITY_TYPE. + */ + public function getCrmEntityId(): int + { + return (int)$this->eventPayload['data']['CRM_ENTITY_ID']; + } + + /** + * @return string Number of external line used to request a callback + */ + public function getLineNumber(): string + { + return $this->eventPayload['data']['LINE_NUMBER']; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/OnExternalCallStart.php b/src/Services/Telephony/Requests/Events/OnExternalCallStart.php new file mode 100644 index 00000000..6361a3c1 --- /dev/null +++ b/src/Services/Telephony/Requests/Events/OnExternalCallStart.php @@ -0,0 +1,95 @@ +eventPayload['data']['USER_ID']; + } + + /** + * @return string Outbound call ID. + */ + public function getPhoneNumber(): string + { + return $this->eventPayload['data']['PHONE_NUMBER']; + } + + /** + * @return string + */ + public function getPhoneNumberInternational(): string + { + return $this->eventPayload['data']['PHONE_NUMBER_INTERNATIONAL']; + } + + /** + * @return \Bitrix24\SDK\Services\Telephony\Common\CrmEntityType + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public function getCrmEntityType(): CrmEntityType + { + return CrmEntityType::initByCode($this->eventPayload['data']['CRM_ENTITY_TYPE']); + } + + /** + * @return int The CRM object ID, which type is specified in CRM_ENTITY_TYPE. + */ + public function getCrmEntityId(): int + { + return (int)$this->eventPayload['data']['CRM_ENTITY_ID']; + } + + /** + * @return int Call list ID, if the call is made from the call list. + */ + public function getCallListId(): int + { + return (int)$this->eventPayload['data']['CALL_LIST_ID']; + } + + /** + * @return string External line number, via which the the call is requested. + */ + public function getLineNumber(): string + { + return $this->eventPayload['data']['LINE_NUMBER']; + } + + /** + * @return string Call ID from the telephony.externalcall.register method. + */ + public function getCallId(): string + { + return $this->eventPayload['data']['CALL_ID']; + } + + /** + * @return string + */ + public function getExtension(): string + { + return $this->eventPayload['data']['EXTENSION']; + } + + /** + * @return bool Defines call as initiated from the mobile app. + */ + public function isMobile(): bool + { + return !($this->eventPayload['data']['IS_MOBILE'] === '0'); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd.php b/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd.php new file mode 100644 index 00000000..ff0229f4 --- /dev/null +++ b/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd.php @@ -0,0 +1,114 @@ +eventPayload['data']['CALL_ID']; + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public function getCallType(): CallType + { + return CallType::initByTypeCode((int)$this->eventPayload['data']['CALL_TYPE']); + } + + /** + * @return string Number used by the subscriber to make a call (if call type is: 2 – Inbound) or number called by the operator (if call type is: 1 – Outbound). + */ + public function getPhoneNumber(): string + { + return $this->eventPayload['data']['PHONE_NUMBER']; + } + + /** + * @return string Number receiving the call (if call type is: 2 – Inbound) or number from which the call was made (if call type is: 1 – Outbound). + */ + public function getPortalNumber(): string + { + return $this->eventPayload['data']['PORTAL_NUMBER']; + } + + /** + * @return int Responding operator ID (if call type is: 2 – Inbound) or identifier of the calling operator (if call type is: 1 – Outbound). + */ + public function getPortalUserId(): int + { + return (int)$this->eventPayload['data']['PORTAL_USER_ID']; + } + + /** + * @return int Call duration. + */ + public function getCallDuration(): int + { + return (int)$this->eventPayload['data']['CALL_DURATION']; + } + + /** + * @return \DateTimeImmutable Date in ISO format. + */ + public function getCallStartDate(): DateTimeImmutable + { + return DateTimeImmutable::createFromFormat(DATE_ATOM, $this->eventPayload['data']['CALL_START_DATE']); + } + + /** + * @return \Money\Money Call cost. + */ + public function getCost(): Money + { + if ($this->eventPayload['COST'] === '') { + return new Money(0, new Currency($this->eventPayload['data']['COST_CURRENCY'])); + } + + return (new DecimalMoneyParser(new ISOCurrencies()))->parse( + $this->eventPayload['data']['COST'], + $this->eventPayload['data']['COST_CURRENCY'] + ); + } + + /** + * @return int Call code (See Call Code Table). + */ + public function getCallFailedCode(): int + { + return (int)$this->eventPayload['data']['CALL_FAILED_CODE']; + } + + /** + * @return string Call code textual description (Latin letters). + */ + public function getCallFailedReason(): string + { + return $this->eventPayload['data']['CALL_FAILED_REASON']; + } + + /** + * @return int + */ + public function getCrmActivityId(): int + { + return (int)$this->eventPayload['data']['CRM_ACTIVITY_ID']; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/OnVoximplantCallInit.php b/src/Services/Telephony/Requests/Events/OnVoximplantCallInit.php new file mode 100644 index 00000000..753f2d67 --- /dev/null +++ b/src/Services/Telephony/Requests/Events/OnVoximplantCallInit.php @@ -0,0 +1,54 @@ +eventPayload['data']['CALL_ID']; + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public function getCallType(): CallType + { + return CallType::initByTypeCode((int)$this->eventPayload['data']['CALL_TYPE']); + } + + /** + * @return string Line ID (numeric for leased PBX, regXXX for cloud hosted PBX, and sipXXX for office PBX). + */ + public function getAccountSearchId(): string + { + return $this->eventPayload['data']['ACCOUNT_SEARCH_ID']; + } + + /** + * @return string Number called by the operator (if call type is: 1 – Outbound) or number called by the subscriber (if call type is: 2 – Inbound). + */ + public function getPhoneNumber(): string + { + return $this->eventPayload['data']['PHONE_NUMBER']; + } + + /** + * @return string Line identifier (if call type is: 1 – Outbound) or telephone number used to make a call to the portal (if call type is: 2 – Inbound). + */ + public function getCallerId(): string + { + return $this->eventPayload['data']['CALLER_ID']; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/OnVoximplantCallStart.php b/src/Services/Telephony/Requests/Events/OnVoximplantCallStart.php new file mode 100644 index 00000000..11df4201 --- /dev/null +++ b/src/Services/Telephony/Requests/Events/OnVoximplantCallStart.php @@ -0,0 +1,29 @@ +eventPayload['data']['CALL_ID']; + } + + /** + * @return int Identifier of the user who responded the call. + */ + public function getUserId(): int + { + return (int)$this->eventPayload['data']['USER_ID']; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Result/CallAttachTranscriptionResult.php b/src/Services/Telephony/Result/CallAttachTranscriptionResult.php new file mode 100644 index 00000000..d68269ca --- /dev/null +++ b/src/Services/Telephony/Result/CallAttachTranscriptionResult.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Telephony\Result; + +use Bitrix24\SDK\Core\Contracts\AddedItemIdResultInterface; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class CallAttachTranscriptionResult extends AbstractResult implements AddedItemIdResultInterface +{ + /** + * @return int + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + + public function getId():int + { + return $this->getCoreResponse()->getResponseData()->getResult()['TRANSCRIPT_ID']; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallFinishItemResult.php b/src/Services/Telephony/Result/ExternalCallFinishItemResult.php new file mode 100644 index 00000000..4057a89d --- /dev/null +++ b/src/Services/Telephony/Result/ExternalCallFinishItemResult.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Telephony\Result; + + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read string $CALL_ID + * @property-read int $EXTERNAL_CALL_ID + * @property-read int $PORTAL_USER_ID + * @property-read string $PHONE_NUMBER + * @property-read string $PORTAL_NUMBER + * @property-read string $INCOMING + * @property-read int $CALL_DURATION + * @property-read array $CALL_START_DATE + * @property-read int $CALL_STATUS + * @property-read int $CALL_VOTE + * @property-read int $COST + * @property-read string $COST_CURRENCY + * @property-read string $CALL_FAILED_CODE + * @property-read string $CALL_FAILED_REASON + * @property-read int $REST_APP_ID + * @property-read bool $REST_APP_NAME + * @property-read int $CRM_ACTIVITY_ID + * @property-read string $COMMENT + * @property-read string $CRM_ENTITY_TYPE + * @property-read int $CRM_ENTITY_ID + * @property-read int $ID + * + */ +class ExternalCallFinishItemResult extends AbstractItem +{ + +} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallFinishResult.php b/src/Services/Telephony/Result/ExternalCallFinishResult.php new file mode 100644 index 00000000..f7622c71 --- /dev/null +++ b/src/Services/Telephony/Result/ExternalCallFinishResult.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Telephony\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class ExternalCallFinishResult extends AbstractResult +{ + /** + * @return \Bitrix24\SDK\Services\Telephony\Result\ExternalCallFinishItemResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function getExternalCallFinish(): ExternalCallFinishItemResult + { + return new ExternalCallFinishItemResult($this->getCoreResponse()->getResponseData()->getResult()); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallHideResult.php b/src/Services/Telephony/Result/ExternalCallHideResult.php new file mode 100644 index 00000000..b1a0661f --- /dev/null +++ b/src/Services/Telephony/Result/ExternalCallHideResult.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Telephony\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class ExternalCallHideResult extends AbstractResult +{ + + /** + * @return bool + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + + public function isHided(): bool + { + return $this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallRecordResult.php b/src/Services/Telephony/Result/ExternalCallRecordResult.php new file mode 100644 index 00000000..7437a324 --- /dev/null +++ b/src/Services/Telephony/Result/ExternalCallRecordResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Telephony\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class ExternalCallRecordResult extends AbstractResult +{ + /** + * @return int + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function getFileId():int + { + return $this->getCoreResponse()->getResponseData()->getResult()['FILE_ID']; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallRegisterItemResult.php b/src/Services/Telephony/Result/ExternalCallRegisterItemResult.php new file mode 100644 index 00000000..ba8a09c2 --- /dev/null +++ b/src/Services/Telephony/Result/ExternalCallRegisterItemResult.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Telephony\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read string $CALL_ID + * @property-read int $CRM_CREATED_LEAD + * @property-read int $CRM_ENTITY_ID + * @property-read string $CRM_ENTITY_TYPE + * @property-read array $CRM_CREATED_ENTITIES + * @property-read string $LEAD_CREATION_ERROR + */ +class ExternalCallRegisterItemResult extends AbstractItem +{ + +} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallRegisterResult.php b/src/Services/Telephony/Result/ExternalCallRegisterResult.php new file mode 100644 index 00000000..232cca7e --- /dev/null +++ b/src/Services/Telephony/Result/ExternalCallRegisterResult.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Telephony\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class ExternalCallRegisterResult extends AbstractResult +{ + /** + * @return \Bitrix24\SDK\Services\Telephony\Result\ExternalCallRegisterItemResult + * @throws BaseException + */ + public function getExternalCallRegister(): ExternalCallRegisterItemResult + { + return new ExternalCallRegisterItemResult($this->getCoreResponse()->getResponseData()->getResult()); + } + +} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesItemResult.php b/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesItemResult.php new file mode 100644 index 00000000..891ef5c2 --- /dev/null +++ b/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesItemResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Telephony\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read string $CRM_ENTITY_TYPE + * @property-read int $CRM_ENTITY_ID + * @property-read int $ASSIGNED_BY_ID + * @property-read string $NAME + * @property-read array $ASSIGNED_BY + */ + +class ExternalCallSearchCrmEntitiesItemResult extends AbstractItem +{ +} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php b/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php new file mode 100644 index 00000000..7d67626c --- /dev/null +++ b/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Telephony\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class ExternalCallSearchCrmEntitiesResult extends AbstractResult +{ + /** + * @return ExternalCallSearchCrmEntitiesItemResult[] + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + + public function getCrmEntitiesSearchResult():array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { + $res[] = new ExternalCallSearchCrmEntitiesItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallShowResult.php b/src/Services/Telephony/Result/ExternalCallShowResult.php new file mode 100644 index 00000000..d275e402 --- /dev/null +++ b/src/Services/Telephony/Result/ExternalCallShowResult.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Telephony\Result; + +use Bitrix24\SDK\Core\Contracts\AddedItemIdResultInterface; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class ExternalCallShowResult extends AbstractResult +{ + + /** + * @return bool + * @throws BaseException + */ + + public function isShown(): bool + { + return $this->getCoreResponse()->getResponseData()->getResult()[0]; + } + + +} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalLineAddResult.php b/src/Services/Telephony/Result/ExternalLineAddResult.php new file mode 100644 index 00000000..c287a5f9 --- /dev/null +++ b/src/Services/Telephony/Result/ExternalLineAddResult.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Telephony\Result; + +use Bitrix24\SDK\Core\Contracts\AddedItemIdResultInterface; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class ExternalLineAddResult extends AbstractResult implements AddedItemIdResultInterface +{ + /** + * @return int + * @throws BaseException + */ + public function getId(): int + { + return $this->getCoreResponse()->getResponseData()->getResult()['ID']; + } + +} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalLineDeleteResult.php b/src/Services/Telephony/Result/ExternalLineDeleteResult.php new file mode 100644 index 00000000..f8f0d570 --- /dev/null +++ b/src/Services/Telephony/Result/ExternalLineDeleteResult.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Telephony\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class ExternalLineDeleteResult extends AbstractResult +{ +} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalLineItemResult.php b/src/Services/Telephony/Result/ExternalLineItemResult.php new file mode 100644 index 00000000..426039d6 --- /dev/null +++ b/src/Services/Telephony/Result/ExternalLineItemResult.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Telephony\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read string $NUMBER + * @property-read string $NAME + */ + +class ExternalLineItemResult extends AbstractItem +{ + +} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalLineUpdateResult.php b/src/Services/Telephony/Result/ExternalLineUpdateResult.php new file mode 100644 index 00000000..3e08575d --- /dev/null +++ b/src/Services/Telephony/Result/ExternalLineUpdateResult.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Telephony\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class ExternalLineUpdateResult extends AbstractResult +{ + /** + * @return int + * @throws BaseException + */ + public function updateExternalLineId():int + { + return (int)$this->getCoreResponse()->getResponseData()->getResult()['ID']; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalLinesResult.php b/src/Services/Telephony/Result/ExternalLinesResult.php new file mode 100644 index 00000000..9345c9eb --- /dev/null +++ b/src/Services/Telephony/Result/ExternalLinesResult.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Telephony\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class ExternalLinesResult extends AbstractResult +{ + /** + * @return ExternalLineItemResult[] + * @throws BaseException + */ + public function getExternalLines(): array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { + $res[] = new ExternalLineItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Service/Call.php b/src/Services/Telephony/Service/Call.php new file mode 100644 index 00000000..f24be08f --- /dev/null +++ b/src/Services/Telephony/Service/Call.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Telephony\Service; + +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Telephony\Result\CallAttachTranscriptionResult; +use Money\Money; + + +class Call extends AbstractService +{ + /** + * The method adds a call transcript. + * + * @param string $callId + * @param Money $callCosts + * @param array> $messages + * @return \Bitrix24\SDK\Services\Telephony\Result\CallAttachTranscriptionResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_call_attachtranscription.php + */ + public function attachTranscription(string $callId, Money $callCosts, array $messages): CallAttachTranscriptionResult + { + return new CallAttachTranscriptionResult( + $this->core->call( + 'telephony.call.attachTranscription', + [ + 'CALL_ID' => $callId, + 'COST' => $this->decimalMoneyFormatter->format($callCosts), + 'COST_CURRENCY' => $callCosts->getCurrency()->getCode(), + 'MESSAGES' => $messages, + ] + ) + ); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Service/ExternalCall.php b/src/Services/Telephony/Service/ExternalCall.php new file mode 100644 index 00000000..96993fb9 --- /dev/null +++ b/src/Services/Telephony/Service/ExternalCall.php @@ -0,0 +1,198 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Telephony\Service; + +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Telephony\Result\ExternalCallFinishResult; +use Bitrix24\SDK\Services\Telephony\Result\ExternalCallRecordResult; +use Bitrix24\SDK\Services\Telephony\Result\ExternalCallRegisterResult; +use Bitrix24\SDK\Services\Telephony\Result\ExternalCallHideResult; +use Bitrix24\SDK\Services\Telephony\Result\ExternalCallSearchCrmEntitiesResult; +use Bitrix24\SDK\Services\Telephony\Result\ExternalCallShowResult; + + +class ExternalCall extends AbstractService +{ + /** + * The method registers a call in Bitrix24 + * + * @param array{ + * USER_PHONE_INNER?: string, + * USER_ID?: int, + * PHONE_NUMBER?: string, + * CALL_START_DATE?: string, + * CRM_CREATE?: int, + * CRM_SOURCE?: string, + * CRM_ENTITY_TYPE?: string, + * CRM_ENTITY_ID?: int, + * SHOW?: int, + * CALL_LIST_ID?: int, + * LINE_NUMBER?: string, + * TYPE?: int, + * } $fields + * + * + * @return \Bitrix24\SDK\Services\Telephony\Result\ExternalCallRegisterResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_register.php + */ + + public function registerCall(array $fields): ExternalCallRegisterResult + { + return new ExternalCallRegisterResult( + $this->core->call( + 'telephony.externalcall.register', + $fields, + ) + ); + } + + /** + * This method displays a call ID screen to the user. + * + * + * @param string $callId + * @param int $userId + * + * @return \Bitrix24\SDK\Services\Telephony\Result\ExternalCallShowResult + * + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_show.php + */ + public function show(string $callId, int $userId): ExternalCallShowResult + { + return new ExternalCallShowResult( + $this->core->call( + 'telephony.externalcall.show', + [ + 'CALL_ID' => $callId, + 'USER_ID' => $userId, + ] + ) + ); + } + + /** + * This method hides call information window. + * + * + * @param string $callId + * @param int $userId + * + * @return \Bitrix24\SDK\Services\Telephony\Result\ExternalCallHideResult + * + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_hide.php + */ + public function hide(string $callId, int $userId): ExternalCallHideResult + { + return new ExternalCallHideResult( + $this->core->call( + 'telephony.externalcall.hide', + [ + 'CALL_ID' => $callId, + 'USER_ID' => $userId, + ] + ) + ); + } + + /** + * Method completes the call, registers it in the statistics and hides the call ID screen from the user. + * + * @param array{ + * CALL_ID?: string, + * USER_ID?: int, + * DURATION?: int, + * COST?: double, + * COST_CURRENCY?: string, + * STATUS_CODE?: string, + * FAILED_REASON?: string, + * RECORD_URL?: string, + * VOTE?: int, + * ADD_TO_CHAT?: int, + * } $fields + * + * @return ExternalCallFinishResult + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_finish.php + */ + public function finish(array $fields): ExternalCallFinishResult + { + return new ExternalCallFinishResult( + $this->core->call( + 'telephony.externalcall.finish', + $fields + ) + ); + } + + /** + * This method connects a record to a finished call and to the call Activity. + * + * @param string $callId + * @param string $fileName + * @param string $fileContent + * @param string|null $recordUrl + * + * @return ExternalCallRecordResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalCall_attachRecord.php + */ + public function attachRecord(string $callId, string $fileName, string $fileContent, ?string $recordUrl = null): ExternalCallRecordResult + { + return new ExternalCallRecordResult( + $this->core->call( + 'telephony.externalCall.attachRecord', + [ + 'CALL_ID' => $callId, + 'FILENAME' => $fileName, + 'FILE_CONTENT' => $fileContent, + 'RECORD_URL' => $recordUrl, + ] + ) + ); + } + + /** + * This method allows to retrieve information about a client from CRM by a telephone number via single request. + * + * If CRM has duplicates by phone, method find and return ONLY one of duplicates + * Method do NOT FIND phones with different phone prefixes +7 or +8 or without it, all phones must by standardised + * + * @param string $phoneNumber + * + * @return ExternalCallSearchCrmEntitiesResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalCall_searchCrmEntities.php + */ + + public function searchCrmEntities(string $phoneNumber): ExternalCallSearchCrmEntitiesResult + { + return new ExternalCallSearchCrmEntitiesResult( + $this->core->call( + 'telephony.externalCall.searchCrmEntities', + [ + 'PHONE_NUMBER'=>$phoneNumber, + ] + ) + ); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Service/ExternalLine.php b/src/Services/Telephony/Service/ExternalLine.php new file mode 100644 index 00000000..056a6a49 --- /dev/null +++ b/src/Services/Telephony/Service/ExternalLine.php @@ -0,0 +1,110 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Telephony\Service; + +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Telephony\Result\ExternalLineAddResult; +use Bitrix24\SDK\Services\Telephony\Result\ExternalLinesResult; +use Bitrix24\SDK\Services\Telephony\Result\ExternalLineDeleteResult; +use Bitrix24\SDK\Services\Telephony\Result\ExternalLineUpdateResult; + + +class ExternalLine extends AbstractService{ + /** + * The method adds an outer line + * + * @param string $lineNumber + * @param string $nameLine + * + * @return \Bitrix24\SDK\Services\Telephony\Result\ExternalLineAddResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalLine_add.php + */ + + public function add(string $lineNumber , string $nameLine): ExternalLineAddResult + { + return new ExternalLineAddResult( + $this->core->call( + 'telephony.externalLine.add', + [ + 'NUMBER' => $lineNumber, + 'NAME' => $nameLine, + ] + ) + ); + } + + /** + * The method adds an outer line + * + * @return ExternalLinesResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalLine_get.php + */ + + public function get(): ExternalLinesResult + { + return new ExternalLinesResult( + $this->core->call('telephony.externalLine.get') + ); + } + + /** + * The method allows you to change the name of the external line + * + * @param string $lineNumber + * @param string $newLineName + * + * @return ExternalLineUpdateResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalLine_update.php + */ + + public function update(string $lineNumber, string $newLineName): ExternalLineUpdateResult + { + return new ExternalLineUpdateResult( + $this->core->call('telephony.externalLine.update', + [ + 'NUMBER' => $lineNumber, + 'NAME' => $newLineName, + ] + ) + ); + } + + /** + * The method for removing an external line. + * + * @param string $lineNumber + * + * @return ExternalLineDeleteResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalLine_delete.php + */ + + public function delete(string $lineNumber): ExternalLineDeleteResult + { + return new ExternalLineDeleteResult( + $this->core->call('telephony.externalLine.delete', + [ + 'NUMBER' => $lineNumber, + ] + ) + ); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/TelephonyServiceBuilder.php b/src/Services/Telephony/TelephonyServiceBuilder.php new file mode 100644 index 00000000..1891a0e3 --- /dev/null +++ b/src/Services/Telephony/TelephonyServiceBuilder.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Telephony; + +use Bitrix24\SDK\Services\AbstractServiceBuilder; +use Bitrix24\SDK\Services\Telephony\Service\Call; +use Bitrix24\SDK\Services\Telephony\Service\ExternalLine; +use Bitrix24\SDK\Services\Telephony\Service\ExternalCall; + + +class TelephonyServiceBuilder extends AbstractServiceBuilder +{ + /** + * @return ExternalLine + */ + public function externalLine(): ExternalLine + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new ExternalLine($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * @return ExternalCall + */ + public function externalCall(): ExternalCall + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new ExternalCall($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * @return Call + */ + public function call(): Call + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Call($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + +} \ No newline at end of file diff --git a/src/Services/UserConsent/Result/UserConsentAgreementItemResult.php b/src/Services/UserConsent/Result/UserConsentAgreementItemResult.php new file mode 100644 index 00000000..90147522 --- /dev/null +++ b/src/Services/UserConsent/Result/UserConsentAgreementItemResult.php @@ -0,0 +1,39 @@ +data[$offset] !== '' && $this->data[$offset] !== null) { + return (int)$this->data[$offset]; + } + + return null; + case 'ACTIVE': + return $this->data[$offset] === 'Y'; + default: + return $this->data[$offset] ?? null; + } + } +} \ No newline at end of file diff --git a/src/Services/UserConsent/Result/UserConsentAgreementResult.php b/src/Services/UserConsent/Result/UserConsentAgreementResult.php new file mode 100644 index 00000000..9738998c --- /dev/null +++ b/src/Services/UserConsent/Result/UserConsentAgreementResult.php @@ -0,0 +1,20 @@ +getCoreResponse()->getResponseData()->getResult()); + } +} \ No newline at end of file diff --git a/src/Services/UserConsent/Result/UserConsentAgreementTextItemResult.php b/src/Services/UserConsent/Result/UserConsentAgreementTextItemResult.php new file mode 100644 index 00000000..099efd59 --- /dev/null +++ b/src/Services/UserConsent/Result/UserConsentAgreementTextItemResult.php @@ -0,0 +1,17 @@ +getCoreResponse()->getResponseData()->getResult()); + } +} \ No newline at end of file diff --git a/src/Services/UserConsent/Result/UserConsentAgreementsResult.php b/src/Services/UserConsent/Result/UserConsentAgreementsResult.php new file mode 100644 index 00000000..0992ef0d --- /dev/null +++ b/src/Services/UserConsent/Result/UserConsentAgreementsResult.php @@ -0,0 +1,26 @@ +getCoreResponse()->getResponseData()->getResult() as $item) { + $res[] = new UserConsentAgreementItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/UserConsent/Service/UserConsent.php b/src/Services/UserConsent/Service/UserConsent.php new file mode 100644 index 00000000..05fc9896 --- /dev/null +++ b/src/Services/UserConsent/Service/UserConsent.php @@ -0,0 +1,27 @@ +core->call('userconsent.consent.add', $consentFields)); + } +} \ No newline at end of file diff --git a/src/Services/UserConsent/Service/UserConsentAgreement.php b/src/Services/UserConsent/Service/UserConsentAgreement.php new file mode 100644 index 00000000..d5418d19 --- /dev/null +++ b/src/Services/UserConsent/Service/UserConsentAgreement.php @@ -0,0 +1,47 @@ +core->call('userconsent.agreement.list')); + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function text(int $agreementId, array $replace): UserConsentAgreementTextResult + { + if (!array_key_exists('button_caption', $replace)) { + throw new InvalidArgumentException('field «button_caption» not found in argument replace '); + } + if (!array_key_exists('fields', $replace)) { + throw new InvalidArgumentException('field «fields» not found in argument replace'); + } + + return new UserConsentAgreementTextResult( + $this->core->call('userconsent.agreement.text', [ + 'id' => $agreementId, + 'replace' => $replace, + ]) + ); + } +} \ No newline at end of file diff --git a/src/Services/UserConsent/UserConsentServiceBuilder.php b/src/Services/UserConsent/UserConsentServiceBuilder.php new file mode 100644 index 00000000..509966d0 --- /dev/null +++ b/src/Services/UserConsent/UserConsentServiceBuilder.php @@ -0,0 +1,40 @@ +serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new UserConsentAgreement($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * get user consent service + * + * @return UserConsent + */ + public function UserConsent(): UserConsent + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new UserConsent($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } +} \ No newline at end of file diff --git a/tests/.env b/tests/.env index 481d15ae..6fc806a2 100644 --- a/tests/.env +++ b/tests/.env @@ -18,4 +18,6 @@ APP_ENV=dev BITRIX24_WEBHOOK= # monolog log level -INTEGRATION_TEST_LOG_LEVEL=200 \ No newline at end of file +INTEGRATION_TEST_LOG_LEVEL=200 +# integration tests assets +INTEGRATION_TEST_OPEN_LINE_CODE=40863c519996e505b5cde98749c97413 \ No newline at end of file diff --git a/tests/Integration/Core/BatchTest.php b/tests/Integration/Core/BatchTest.php index 6221f217..1aaf427e 100644 --- a/tests/Integration/Core/BatchTest.php +++ b/tests/Integration/Core/BatchTest.php @@ -296,7 +296,7 @@ public function testBatchAddEntityItems(): void // add deals to bitrix24 $dealIdList = []; foreach ($this->batch->addEntityItems('crm.deal.add', $rawDeals) as $cnt => $addDealResult) { - $dealIdList[] = $addDealResult->getResult()->getResultData()[0]; + $dealIdList[] = $addDealResult->getResult()[0]; } $this->assertCount(self::DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE, $dealIdList); } @@ -335,14 +335,14 @@ public function testBatchDeleteEntityItems(): void // add deals to bitrix24 $dealIdList = []; foreach ($this->batch->addEntityItems('crm.deal.add', $rawDeals) as $cnt => $addDealResult) { - $dealIdList[] = $addDealResult->getResult()->getResultData()[0]; + $dealIdList[] = $addDealResult->getResult()[0]; } $this->assertCount(self::DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE, $dealIdList); // delete deals from bitrix24 $dealsDeleteResult = []; foreach ($this->batch->deleteEntityItems('crm.deal.delete', $dealIdList) as $cnt => $deleteDealResult) { - $dealsDeleteResult[] = $deleteDealResult->getResult()->getResultData()[0]; + $dealsDeleteResult[] = $deleteDealResult->getResult()[0]; } $this->assertCount(self::DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE, $dealsDeleteResult); } @@ -356,7 +356,7 @@ public function testBatchDeleteEntityItemsWithWrongTypeOfEntityId(): void { $this->expectException(InvalidArgumentException::class); foreach ($this->batch->deleteEntityItems('crm.deal.delete', [1, 2, '3', 4, 5]) as $cnt => $deleteDealResult) { - $dealsDeleteResult[] = $deleteDealResult->getResult()->getResultData()[0]; + $dealsDeleteResult[] = $deleteDealResult->getResult()[0]; } } diff --git a/tests/Integration/Core/CoreTest.php b/tests/Integration/Core/CoreTest.php index 0d8d9132..5b590193 100644 --- a/tests/Integration/Core/CoreTest.php +++ b/tests/Integration/Core/CoreTest.php @@ -25,7 +25,7 @@ class CoreTest extends TestCase public function testCallExistingApiMethod(): void { $response = $this->core->call('app.info'); - $this->assertIsArray($response->getResponseData()->getResult()->getResultData()); + $this->assertIsArray($response->getResponseData()->getResult()); } /** diff --git a/tests/Integration/Fabric.php b/tests/Integration/Fabric.php index dcf0e876..3d2357c9 100644 --- a/tests/Integration/Fabric.php +++ b/tests/Integration/Fabric.php @@ -9,6 +9,8 @@ use Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface; use Bitrix24\SDK\Core\Contracts\CoreInterface; use Bitrix24\SDK\Core\CoreBuilder; +use Bitrix24\SDK\Core\Credentials\Credentials; +use Bitrix24\SDK\Core\Credentials\WebhookUrl; use Bitrix24\SDK\Services\ServiceBuilder; use Monolog\Handler\StreamHandler; use Monolog\Logger; @@ -32,6 +34,14 @@ public static function getServiceBuilder(): ServiceBuilder return new ServiceBuilder(self::getCore(), self::getBatchService(), self::getBulkItemsReader(), self::getLogger()); } + /** + * @return string + */ + public static function getOpenLineCode(): string + { + return (string)$_ENV['INTEGRATION_TEST_OPEN_LINE_CODE']; + } + /** * @return \Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException @@ -49,7 +59,11 @@ public static function getCore(): CoreInterface { return (new CoreBuilder()) ->withLogger(self::getLogger()) - ->withWebhookUrl($_ENV['BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK'] ?? $_ENV['BITRIX24_WEBHOOK']) + ->withCredentials( + Credentials::createFromWebhook( + new WebhookUrl($_ENV['BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK'] ?? $_ENV['BITRIX24_WEBHOOK']) + ) + ) ->build(); } diff --git a/tests/Integration/Services/CRM/Activity/ReadModel/EmailFetcherTest.php b/tests/Integration/Services/CRM/Activity/ReadModel/EmailFetcherTest.php new file mode 100644 index 00000000..c8bf7ed9 --- /dev/null +++ b/tests/Integration/Services/CRM/Activity/ReadModel/EmailFetcherTest.php @@ -0,0 +1,40 @@ +emailFetcher->getList(['ID' => 'DESC'], [], ['*', 'COMMUNICATIONS',], 5) as $item) { + $itemsCnt++; +// print(sprintf( +// '%s | %s | %s ', +// $item->PROVIDER_TYPE_ID, +// $item->CREATED, +// $item->SUBJECT, +// ) . PHP_EOL); + } + $this->assertTrue(true); + } + + public function setUp(): void + { + $this->emailFetcher = Fabric::getServiceBuilder()->getCRMScope()->activityFetcher()->emailFetcher(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Activity/ReadModel/OpenLineFetcherTest.php b/tests/Integration/Services/CRM/Activity/ReadModel/OpenLineFetcherTest.php new file mode 100644 index 00000000..10628ad5 --- /dev/null +++ b/tests/Integration/Services/CRM/Activity/ReadModel/OpenLineFetcherTest.php @@ -0,0 +1,40 @@ +openLineFetcher->getList(['ID' => 'DESC'], [], ['*', 'COMMUNICATIONS',], null, 5) as $item) { + $itemsCnt++; +// print(sprintf( +// '%s | %s | %s ', +// $item->PROVIDER_TYPE_ID, +// $item->CREATED, +// $item->SUBJECT, +// ) . PHP_EOL); + } + $this->assertTrue(true); + } + + public function setUp(): void + { + $this->openLineFetcher = Fabric::getServiceBuilder()->getCRMScope()->activityFetcher()->openLineFetcher(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Activity/ReadModel/VoximplantFetcherTest.php b/tests/Integration/Services/CRM/Activity/ReadModel/VoximplantFetcherTest.php new file mode 100644 index 00000000..6ad0af15 --- /dev/null +++ b/tests/Integration/Services/CRM/Activity/ReadModel/VoximplantFetcherTest.php @@ -0,0 +1,41 @@ +voximplantFetcher->getList(['ID' => 'DESC'], [], ['*', 'COMMUNICATIONS',], 5) as $item) { + $itemsCnt++; +// print(sprintf( +// '%s | %s | %s ', +// $item->PROVIDER_TYPE_ID, +// $item->CREATED, +// $item->SUBJECT, +// ) . PHP_EOL); + } + $this->assertTrue(true); + } + + public function setUp(): void + { + $this->voximplantFetcher = Fabric::getServiceBuilder()->getCRMScope()->activityFetcher()->voximplantFetcher(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Activity/ReadModel/WebFormFetcherTest.php b/tests/Integration/Services/CRM/Activity/ReadModel/WebFormFetcherTest.php new file mode 100644 index 00000000..f3a9b942 --- /dev/null +++ b/tests/Integration/Services/CRM/Activity/ReadModel/WebFormFetcherTest.php @@ -0,0 +1,40 @@ +webFormFetcher->getList(['ID' => 'DESC'], [], ['*', 'COMMUNICATIONS',], null, 5) as $item) { + $itemsCnt++; +// print(sprintf( +// '%s | %s | %s ', +// $item->PROVIDER_TYPE_ID, +// $item->CREATED, +// $item->SUBJECT, +// ) . PHP_EOL); + } + $this->assertTrue(true); + } + + public function setUp(): void + { + $this->webFormFetcher = Fabric::getServiceBuilder()->getCRMScope()->activityFetcher()->webFormFetcher(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Activity/Service/ActivityTest.php b/tests/Integration/Services/CRM/Activity/Service/ActivityTest.php new file mode 100644 index 00000000..f0b0acfc --- /dev/null +++ b/tests/Integration/Services/CRM/Activity/Service/ActivityTest.php @@ -0,0 +1,267 @@ +contactService->add(['NAME' => 'test contact'])->getId(); + $this->contactId[] = $contactId; + $this->activityId[] = $this->activityService->add( + [ + 'OWNER_ID' => $contactId, + 'OWNER_TYPE_ID' => 3, + 'TYPE_ID' => 2, + 'PROVIDER_ID' => 'VOXIMPLANT_CALL', + 'PROVIDER_TYPE_ID' => 'CALL', + 'SUBJECT' => 'test activity', + 'DESCRIPTION' => 'test activity description', + 'DESCRIPTION_TYPE' => '1', + 'DIRECTION' => '2', + 'COMMUNICATIONS' => [ + 0 => [ + 'TYPE' => 'PHONE', + 'VALUE' => '+79780194444', + ], + ], + ] + )->getId(); + // successfully add activity + $this->assertTrue(true); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Activity\Service\Activity::delete + */ + public function testDelete(): void + { + $contactId = $this->contactService->add(['NAME' => 'test contact'])->getId(); + $this->contactId[] = $contactId; + $activityId = $this->activityService->add( + [ + 'OWNER_ID' => $contactId, + 'OWNER_TYPE_ID' => 3, + 'TYPE_ID' => 2, + 'PROVIDER_ID' => 'VOXIMPLANT_CALL', + 'PROVIDER_TYPE_ID' => 'CALL', + 'SUBJECT' => 'test activity', + 'DESCRIPTION' => 'test activity description', + 'DESCRIPTION_TYPE' => '1', + 'DIRECTION' => '2', + 'COMMUNICATIONS' => [ + 0 => [ + 'TYPE' => 'PHONE', + 'VALUE' => '+79780194444', + ], + ], + ] + )->getId(); + $this->assertTrue($this->activityService->delete($activityId)->isSuccess()); + } + + /** + * @covers Contact::fields + * @throws BaseException + * @throws TransportException + */ + public function testFields(): void + { + self::assertIsArray($this->activityService->fields()->getFieldsDescription()); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Activity\Service\Activity::get + */ + public function testGet(): void + { + $contactId = $this->contactService->add(['NAME' => 'test contact'])->getId(); + $this->contactId[] = $contactId; + + $newActivity = [ + 'OWNER_ID' => $contactId, + 'OWNER_TYPE_ID' => 3, + 'TYPE_ID' => 2, + 'PROVIDER_ID' => 'VOXIMPLANT_CALL', + 'PROVIDER_TYPE_ID' => 'CALL', + 'SUBJECT' => 'test activity', + 'DESCRIPTION' => 'test activity description', + 'DESCRIPTION_TYPE' => '1', + 'DIRECTION' => '2', + 'COMMUNICATIONS' => [ + 0 => [ + 'TYPE' => 'PHONE', + 'VALUE' => '+79780194444', + ], + ], + ]; + $activityId = $this->activityService->add($newActivity)->getId(); + $this->activityId[] = $activityId; + + $activity = $this->activityService->get($activityId)->activity(); + + $this->assertEquals($newActivity['OWNER_ID'], $activity->OWNER_ID); + $this->assertEquals($newActivity['SUBJECT'], $activity->SUBJECT); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Activity\Service\Activity::list + */ + public function testList(): void + { + $contactId = $this->contactService->add(['NAME' => 'test contact'])->getId(); + $this->contactId[] = $contactId; + + $newActivity = []; + for ($i = 1; $i < 10; $i++) { + $newActivity[$i] = [ + 'OWNER_ID' => $contactId, + 'OWNER_TYPE_ID' => 3, + 'TYPE_ID' => 2, + 'PROVIDER_ID' => 'VOXIMPLANT_CALL', + 'PROVIDER_TYPE_ID' => 'CALL', + 'SUBJECT' => sprintf('test activity - %s', $i), + 'DESCRIPTION' => 'test activity description', + 'DESCRIPTION_TYPE' => '1', + 'DIRECTION' => '2', + 'COMMUNICATIONS' => [ + 0 => [ + 'TYPE' => 'PHONE', + 'VALUE' => '+79780194444', + ], + ], + ]; + $this->activityId[] = $this->activityService->add($newActivity[$i])->getId();; + } + + $res = $this->activityService->list( + ['ID' => 'DESC'], + [ + 'OWNER_ID' => $contactId, + ], + ["*", "COMMUNICATIONS"], + 0 + ); + $this->assertEquals(count($newActivity), count($res->getActivities())); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Activity\Service\Activity::update + */ + public function testUpdate(): void + { + $contactId = $this->contactService->add(['NAME' => 'test contact'])->getId(); + $this->contactId[] = $contactId; + + $newActivity = [ + 'OWNER_ID' => $contactId, + 'OWNER_TYPE_ID' => 3, + 'TYPE_ID' => 2, + 'PROVIDER_ID' => 'VOXIMPLANT_CALL', + 'PROVIDER_TYPE_ID' => 'CALL', + 'SUBJECT' => 'test activity', + 'DESCRIPTION' => 'test activity description', + 'DESCRIPTION_TYPE' => '1', + 'DIRECTION' => '2', + 'COMMUNICATIONS' => [ + 0 => [ + 'TYPE' => 'PHONE', + 'VALUE' => '+79780194444', + ], + ], + ]; + $activityId = $this->activityService->add($newActivity)->getId(); + $this->activityId[] = $activityId; + + $subject = 'qqqqq'; + $this->activityService->update($activityId, [ + 'SUBJECT' => $subject, + ]); + + $this->assertEquals($subject, $this->activityService->get($activityId)->activity()->SUBJECT); + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function testCountByFilter(): void + { + $contactId = $this->contactService->add(['NAME' => 'test contact'])->getId(); + $this->contactId[] = $contactId; + + $newActivity = []; + for ($i = 1; $i < 10; $i++) { + $newActivity[$i] = [ + 'OWNER_ID' => $contactId, + 'OWNER_TYPE_ID' => 3, + 'TYPE_ID' => 2, + 'PROVIDER_ID' => 'VOXIMPLANT_CALL', + 'PROVIDER_TYPE_ID' => 'CALL', + 'SUBJECT' => sprintf('test activity - %s', $i), + 'DESCRIPTION' => 'test activity description', + 'DESCRIPTION_TYPE' => '1', + 'DIRECTION' => '2', + 'COMMUNICATIONS' => [ + 0 => [ + 'TYPE' => 'PHONE', + 'VALUE' => '+79780194444', + ], + ], + ]; + $this->activityId[] = $this->activityService->add($newActivity[$i])->getId();; + } + + $this->assertEquals( + count($newActivity), + $this->activityService->countByFilter( + [ + 'OWNER_ID' => $contactId, + ] + ) + ); + } + + public function tearDown(): void + { + foreach ($this->activityService->batch->delete($this->activityId) as $result) { + } + foreach ($this->contactService->batch->delete($this->contactId) as $result) { + } + } + + public function setUp(): void + { + $this->activityService = Fabric::getServiceBuilder()->getCRMScope()->activity(); + $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); + $this->contactId = []; + $this->activityId = []; + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Activity/Service/BatchTest.php b/tests/Integration/Services/CRM/Activity/Service/BatchTest.php new file mode 100644 index 00000000..f848cb7e --- /dev/null +++ b/tests/Integration/Services/CRM/Activity/Service/BatchTest.php @@ -0,0 +1,189 @@ +contactService->add(['NAME' => 'test contact'])->getId(); + $this->contactId[] = $contactId; + + $items = []; + for ($i = 1; $i < self::BATCH_TEST_ELEMENTS_COUNT; $i++) { + $items[] = [ + 'OWNER_ID' => $contactId, + 'OWNER_TYPE_ID' => 3, + 'TYPE_ID' => 2, + 'PROVIDER_ID' => 'VOXIMPLANT_CALL', + 'PROVIDER_TYPE_ID' => 'CALL', + 'SUBJECT' => 'test activity', + 'DESCRIPTION' => 'test activity description', + 'DESCRIPTION_TYPE' => '1', + 'DIRECTION' => '2', + 'COMMUNICATIONS' => [ + 0 => [ + 'TYPE' => 'PHONE', + 'VALUE' => '+79780194444', + ], + ], + ]; + } + + $cnt = 0; + $activityId = []; + foreach ($this->activityService->batch->add($items) as $item) { + $cnt++; + $activityId[] = $item->getId(); + } + self::assertEquals(count($items), $cnt); + + $cnt = 0; + foreach ($this->activityService->batch->delete($activityId) as $cnt => $deleteResult) { + $cnt++; + } + self::assertEquals(count($items), $cnt); + } + + /** + * @testdox Batch delete activities + * @covers \Bitrix24\SDK\Services\CRM\Activity\Service\Batch::delete() + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function testBatchDelete(): void + { + $contactId = $this->contactService->add(['NAME' => 'test contact'])->getId(); + $this->contactId[] = $contactId; + + $items = []; + for ($i = 1; $i < self::BATCH_TEST_ELEMENTS_COUNT; $i++) { + $items[] = [ + 'OWNER_ID' => $contactId, + 'OWNER_TYPE_ID' => 3, + 'TYPE_ID' => 2, + 'PROVIDER_ID' => 'VOXIMPLANT_CALL', + 'PROVIDER_TYPE_ID' => 'CALL', + 'SUBJECT' => 'test activity', + 'DESCRIPTION' => 'test activity description', + 'DESCRIPTION_TYPE' => '1', + 'DIRECTION' => '2', + 'COMMUNICATIONS' => [ + 0 => [ + 'TYPE' => 'PHONE', + 'VALUE' => '+79780194444', + ], + ], + ]; + } + + $cnt = 0; + $activityId = []; + foreach ($this->activityService->batch->add($items) as $item) { + $cnt++; + $activityId[] = $item->getId(); + } + self::assertEquals(count($items), $cnt); + + $cnt = 0; + foreach ($this->activityService->batch->delete($activityId) as $cnt => $deleteResult) { + $cnt++; + } + self::assertEquals(count($items), $cnt); + + + $this->assertEquals( + 0, + $this->activityService->countByFilter( + [ + 'OWNER_ID' => $contactId, + ] + ) + ); + } + + /** + * @testdox Batch list deals + * @covers \Bitrix24\SDK\Services\CRM\Contact\Service\Batch::list() + * @throws BaseException + * @throws TransportException + */ + public function testBatchList(): void + { + $contactId = $this->contactService->add(['NAME' => 'test contact'])->getId(); + $this->contactId[] = $contactId; + + $items = []; + for ($i = 1; $i < self::BATCH_TEST_ELEMENTS_COUNT; $i++) { + $items[] = [ + 'OWNER_ID' => $contactId, + 'OWNER_TYPE_ID' => 3, + 'TYPE_ID' => 2, + 'PROVIDER_ID' => 'VOXIMPLANT_CALL', + 'PROVIDER_TYPE_ID' => 'CALL', + 'SUBJECT' => 'test activity', + 'DESCRIPTION' => 'test activity description', + 'DESCRIPTION_TYPE' => '1', + 'DIRECTION' => '2', + 'COMMUNICATIONS' => [ + 0 => [ + 'TYPE' => 'PHONE', + 'VALUE' => '+79780194444', + ], + ], + ]; + } + + $cnt = 0; + $activityId = []; + foreach ($this->activityService->batch->add($items) as $item) { + $cnt++; + $activityId[] = $item->getId(); + } + + //fetch items + $itemsCnt = 0; + foreach ($this->activityService->batch->list(['ID' => 'DESC'], ['OWNER_ID' => $contactId], ['*']) as $item) { + $itemsCnt++; + } + $this->assertEquals( + count($activityId), + $itemsCnt, + sprintf( + 'batch activity list not fetched, expected %s, actual %s', + count($activityId), + $itemsCnt + ) + ); + } + + public function tearDown(): void + { + $this->contactService->batch->delete($this->contactId); + } + + public function setUp(): void + { + $this->activityService = Fabric::getServiceBuilder()->getCRMScope()->activity(); + $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); + $this->contactId = []; + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Deal/Service/BatchTest.php b/tests/Integration/Services/CRM/Deal/Service/BatchTest.php index f50524bb..08c19dbd 100644 --- a/tests/Integration/Services/CRM/Deal/Service/BatchTest.php +++ b/tests/Integration/Services/CRM/Deal/Service/BatchTest.php @@ -90,6 +90,55 @@ public function testBatchDelete(): void self::assertEquals(count($deals), $cnt); } + /** + * @testdox Batch delete deals + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\Batch::update() + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Exception + */ + public function testBatchUpdate(): void + { + // add deals + $deals = []; + for ($i = 1; $i < 60; $i++) { + $deals[] = ['TITLE' => 'TITLE-' . $i]; + } + $cnt = 0; + $dealId = []; + foreach ($this->dealService->batch->add($deals) as $item) { + $cnt++; + $dealId[] = $item->getId(); + } + self::assertEquals(count($deals), $cnt); + + // read deals and prepare update information + $dealsToUpdate = []; + $resultDeals = []; + foreach ($this->dealService->batch->list([], ['ID' => $dealId], ['ID', 'TITLE', 'OPPORTUNITY']) as $deal) { + $dealOpportunity = random_int(100, 10000); + $dealsToUpdate[$deal->ID] = [ + 'fields' => [ + 'OPPORTUNITY' => $dealOpportunity, + ], + 'params' => [], + ]; + $resultDeals[$deal->ID] = $dealOpportunity; + } + + // update deals + foreach ($this->dealService->batch->update($dealsToUpdate) as $dealUpdateResult) { + $this->assertTrue($dealUpdateResult->isSuccess()); + } + + // list deals + $updateResult = []; + foreach ($this->dealService->batch->list([], ['ID' => $dealId], ['ID', 'TITLE', 'OPPORTUNITY']) as $deal) { + $updateResult[$deal->ID] = $deal->OPPORTUNITY; + } + + $this->assertEquals($resultDeals, $updateResult); + } + public function setUp(): void { $this->dealService = Fabric::getServiceBuilder()->getCRMScope()->deal(); diff --git a/tests/Integration/Services/CRM/Lead/Service/BatchTest.php b/tests/Integration/Services/CRM/Lead/Service/BatchTest.php new file mode 100644 index 00000000..8792fab2 --- /dev/null +++ b/tests/Integration/Services/CRM/Lead/Service/BatchTest.php @@ -0,0 +1,97 @@ +leadService->add(['TITLE' => 'test lead'])->getId(); + $cnt = 0; + + foreach ($this->leadService->batch->list([], ['ID' => $itemId], ['ID', 'NAME'], 1) as $item) { + $cnt++; + } + self::assertGreaterThanOrEqual(1, $cnt); + + $this->leadService->delete($itemId); + } + + /** + * @testdox Batch add lead + * @covers \Bitrix24\SDK\Services\CRM\Lead\Service\Batch::add() + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function testBatchAdd(): void + { + $items = []; + for ($i = 1; $i < 60; $i++) { + $items[] = ['TITLE' => 'TITLE-' . $i]; + } + $cnt = 0; + $itemId = []; + foreach ($this->leadService->batch->add($items) as $item) { + $cnt++; + $itemId[] = $item->getId(); + } + self::assertEquals(count($items), $cnt); + + $cnt = 0; + foreach ($this->leadService->batch->delete($itemId) as $cnt => $deleteResult) { + $cnt++; + } + self::assertEquals(count($items), $cnt); + } + + /** + * @testdox Batch delete deals + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\Batch::add() + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function testBatchDelete(): void + { + $deals = []; + for ($i = 1; $i < 60; $i++) { + $deals[] = ['TITLE' => 'TITLE-' . $i]; + } + $cnt = 0; + $dealId = []; + foreach ($this->leadService->batch->add($deals) as $item) { + $cnt++; + $dealId[] = $item->getId(); + } + self::assertEquals(count($deals), $cnt); + + $cnt = 0; + foreach ($this->leadService->batch->delete($dealId) as $cnt => $deleteResult) { + $cnt++; + } + self::assertEquals(count($deals), $cnt); + } + + public function setUp(): void + { + $this->leadService = Fabric::getServiceBuilder()->getCRMScope()->lead(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Lead/Service/LeadTest.php b/tests/Integration/Services/CRM/Lead/Service/LeadTest.php new file mode 100644 index 00000000..9891e483 --- /dev/null +++ b/tests/Integration/Services/CRM/Lead/Service/LeadTest.php @@ -0,0 +1,119 @@ +leadService->add(['TITLE' => 'test lead'])->getId()); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers Lead::delete + */ + public function testDelete(): void + { + self::assertTrue($this->leadService->delete($this->leadService->add(['TITLE' => 'test lead'])->getId())->isSuccess()); + } + + /** + * @covers Lead::fields + * @throws BaseException + * @throws TransportException + */ + public function testFields(): void + { + self::assertIsArray($this->leadService->fields()->getFieldsDescription()); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers Lead::get + */ + public function testGet(): void + { + self::assertGreaterThan( + 1, + $this->leadService->get($this->leadService->add(['TITLE' => 'test Lead'])->getId())->lead()->ID + ); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers Lead::list + */ + public function testList(): void + { + $this->leadService->add(['TITLE' => 'test']); + self::assertGreaterThanOrEqual(1, $this->leadService->list([], [], ['ID', 'TITLE'])->getLeads()); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers Lead::update + */ + public function testUpdate(): void + { + $deal = $this->leadService->add(['TITLE' => 'test lead']); + $newTitle = 'test2'; + + self::assertTrue($this->leadService->update($deal->getId(), ['TITLE' => $newTitle], [])->isSuccess()); + self::assertEquals($newTitle, $this->leadService->get($deal->getId())->lead()->TITLE); + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\Deal::countByFilter + */ + public function testCountByFilter(): void + { + $before = $this->leadService->countByFilter(); + + $newItemsCount = 60; + $items = []; + for ($i = 1; $i <= $newItemsCount; $i++) { + $items[] = ['TITLE' => 'TITLE-' . $i]; + } + $cnt = 0; + foreach ($this->leadService->batch->add($items) as $item) { + $cnt++; + } + self::assertEquals(count($items), $cnt); + + $after = $this->leadService->countByFilter(); + + $this->assertEquals($before + $newItemsCount, $after); + } + + public function setUp(): void + { + $this->leadService = Fabric::getServiceBuilder()->getCRMScope()->lead(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/IMOpenLines/Service/NetworkTest.php b/tests/Integration/Services/IMOpenLines/Service/NetworkTest.php new file mode 100644 index 00000000..80948a9e --- /dev/null +++ b/tests/Integration/Services/IMOpenLines/Service/NetworkTest.php @@ -0,0 +1,50 @@ +networkService->join(Fabric::getOpenLineCode()); + $this->assertGreaterThanOrEqual(1, $res->getId()); + } + + /** + * @covers \Bitrix24\SDK\Services\IMOpenLines\Service\Network::join + * @testdox test get agreements list + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function testMessageAdd(): void + { + $res = $this->networkService->messageAdd( + Fabric::getOpenLineCode(), + (int)$this->networkService->core->call('PROFILE')->getResponseData()->getResult()['ID'], + sprintf('Test message at %s', time()) + ); + + $this->assertTrue($res->isSuccess()); + } + + public function setUp(): void + { + $this->networkService = Fabric::getServiceBuilder()->getIMOpenLinesScope()->Network(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/Main/Service/MainTest.php b/tests/Integration/Services/Main/Service/MainTest.php new file mode 100644 index 00000000..d4bd3adc --- /dev/null +++ b/tests/Integration/Services/Main/Service/MainTest.php @@ -0,0 +1,116 @@ +mainService->getServerTime()->time(); + $this->assertTrue(true); + } + + /** + * @covers \Bitrix24\SDK\Services\Main\Service\Main::getCurrentUserProfile + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function testGetCurrentUserProfile(): void + { + $profile = $this->mainService->getCurrentUserProfile()->getUserProfile(); + $this->assertTrue($profile->ADMIN); + } + + /** + * @covers \Bitrix24\SDK\Services\Main\Service\Main::isCurrentUserHasAdminRights + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function testIsUserIsAdmin(): void + { + $this->assertTrue($this->mainService->isCurrentUserHasAdminRights()->isAdmin()); + } + + /** + * @covers \Bitrix24\SDK\Services\Main\Service\Main::getMethodAffordability + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function testMethodGetInformationForNonExistsMethod(): void + { + $this->assertFalse($this->mainService->getMethodAffordability('app.info1')->isAvailable()); + $this->assertFalse($this->mainService->getMethodAffordability('app.info1')->isExisting()); + } + + /** + * @covers \Bitrix24\SDK\Services\Main\Service\Main::getApplicationInfo + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function testApplicationInfo(): void + { + $this->assertIsString($this->mainService->getApplicationInfo()->applicationInfo()->LICENSE); + } + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException + */ + public function testGetAvailableScope(): void + { + $scope = new Scope($this->mainService->getAvailableScope()->getResponseData()->getResult()); + $this->assertIsArray($scope->getScopeCodes()); + } + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException + */ + public function testGetCurrentScope(): void + { + $this->assertGreaterThanOrEqual( + count((new Scope($this->mainService->getCurrentScope()->getResponseData()->getResult()))->getScopeCodes()), + count((new Scope($this->mainService->getAvailableScope()->getResponseData()->getResult()))->getScopeCodes()) + ); + } + + /** + * @covers \Bitrix24\SDK\Services\Main\Service\Main::getAvailableMethods + * @testdox test methods list + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function testGetAvailableMethods(): void + { + $this->assertIsArray($this->mainService->getAvailableMethods()->getResponseData()->getResult()); + } + + public function setUp(): void + { + $this->mainService = Fabric::getServiceBuilder()->getMainScope()->main(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/Service/CallTest.php b/tests/Integration/Services/Telephony/Service/CallTest.php new file mode 100644 index 00000000..1993a385 --- /dev/null +++ b/tests/Integration/Services/Telephony/Service/CallTest.php @@ -0,0 +1,139 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Tests\Integration\Services\Telephony\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\CRM\Contact\Service\Contact; +use Bitrix24\SDK\Services\CRM\Lead\Service\Lead; +use Bitrix24\SDK\Services\Main\Service\Main; +use Bitrix24\SDK\Services\Telephony\Common\CallType; +use Bitrix24\SDK\Services\Telephony\Common\CrmEntityType; +use Bitrix24\SDK\Services\Telephony\Common\StatusSipCodeInterface; +use Bitrix24\SDK\Services\Telephony\Service\Call; +use Bitrix24\SDK\Services\Telephony\Service\ExternalCall; +use Bitrix24\SDK\Tests\Integration\Fabric; +use DateTime; +use DateTimeInterface; +use Exception; +use Money\Currencies\ISOCurrencies; +use Money\Currency; +use Money\Formatter\DecimalMoneyFormatter; +use Money\Formatter\IntlMoneyFormatter; +use Money\Money; +use PHPUnit\Framework\TestCase; + +class CallTest extends TestCase +{ + protected Call $callService; + protected Lead $leadService; + protected ExternalCall $externalCallService; + protected Main $mainService; + protected Contact $contactService; + + + /** + * @throws BaseException + * @throws TransportException + * @throws Exception + * @covers Call::attachTranscription + */ + public function testAttachTranscription(): void + { + $datetime = new DateTime('now'); + $callStartDate = $datetime->format(DateTimeInterface::ATOM); + $phoneNumber = sprintf('+7%s', time()); + $callCosts = new Money(1000, new Currency('RUB')); + $currencies = new ISOCurrencies(); + + $moneyFormatter = new DecimalMoneyFormatter($currencies); + + + $contactId = $this->contactService->add( + [ + 'NAME' => 'Глеб', + 'SECOND_NAME' => 'Егорович', + 'PHONE' => [ + [ + 'VALUE' => $phoneNumber, + 'VALUE_TYPE' => 'WORK' + ] + ] + ] + )->getId(); + + $userId = $this->mainService->getCurrentUserProfile()->getUserProfile()->ID; + + $messages = [ + [ + 'SIDE' => 'User', + 'START_TIME' => 1, + 'STOP_TIME' => 3, + 'MESSAGE' => 'HELLO WORLD' + ], + [ + 'SIDE' => "Client", + 'START_TIME' => 4, + 'STOP_TIME' => 8, + 'MESSAGE' => "Здравствуйте, вы продаете пылесосы?" + ], + ]; + + $registerCallResult = $this->externalCallService->registerCall([ + 'USER_PHONE_INNER' => '14', + 'USER_ID' => $userId, + 'PHONE_NUMBER' => $phoneNumber, + 'CALL_START_DATE' => $callStartDate, + 'CRM_CREATE' => 0, + 'CRM_SOURCE' => '1', + 'CRM_ENTITY_TYPE' => (string)CrmEntityType::contact(), + 'CRM_ENTITY_ID' => $contactId, + 'SHOW' => 1, + 'CALL_LIST_ID' => 1, + 'LINE_NUMBER' => $phoneNumber, + 'TYPE' => (string)CallType::outboundCall(), + ])->getExternalCallRegister(); + $finishCallResult = $this->externalCallService->finish([ + 'CALL_ID' => $registerCallResult->CALL_ID, + 'USER_ID' => $userId, + 'DURATION' => 255, + 'COST' => $moneyFormatter->format($callCosts), + 'COST_CURRENCY' => $callCosts->getCurrency()->getCode(), + 'STATUS_CODE' => StatusSipCodeInterface::STATUS_OK, + 'FAILED_REASON' => '', + 'RECORD_URL' => '', + 'VOTE' => 5, + 'ADD_TO_CHAT' => 1 + ])->getExternalCallFinish(); + + self::assertGreaterThan(1, + $this->callService->attachTranscription( + $registerCallResult->CALL_ID, + $callCosts, + $messages)->getId() + ); + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public function setUp(): void + { + $this->callService = Fabric::getServiceBuilder()->getTelephonyScope()->call(); + $this->externalCallService = Fabric::getServiceBuilder()->getTelephonyScope()->externalCall(); + $this->leadService = Fabric::getServiceBuilder()->getCRMScope()->lead(); + $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); + $this->mainService = Fabric::getServiceBuilder()->getMainScope()->main(); + } + +} \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php new file mode 100644 index 00000000..efe6436f --- /dev/null +++ b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php @@ -0,0 +1,308 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Tests\Integration\Services\Telephony\Service; + + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\CRM\Contact\Service\Contact; +use Bitrix24\SDK\Services\CRM\Lead\Service\Lead; +use Bitrix24\SDK\Services\Main\Service\Main; +use Bitrix24\SDK\Services\Telephony\Common\CallType; +use Bitrix24\SDK\Services\Telephony\Common\CrmEntityType; +use Bitrix24\SDK\Services\Telephony\Common\StatusSipCodeInterface; +use Bitrix24\SDK\Services\Telephony\Service\ExternalCall; +use Bitrix24\SDK\Tests\Integration\Fabric; +use DateTime; +use DateTimeInterface; +use Exception; +use PHPUnit\Framework\TestCase; + +class ExternalCallTest extends TestCase +{ + protected Lead $leadService; + protected ExternalCall $externalCallService; + private Main $mainService; + protected Contact $contactService; + + /** + * @throws BaseException + * @throws TransportException + * @throws Exception + * @covers ExternalCall::registerCall + */ + + public function testRegisterCall(): void + { + $datetime = new DateTime('now'); + $callStartDate = $datetime->format(DateTimeInterface::ATOM); + $phoneNumber = sprintf('+7%s', time()); + $leadId = $this->leadService->add( + [ + 'TITLE' => 'test lead', + 'PHONE' => [ + [ + 'VALUE' => $phoneNumber, + 'VALUE_TYPE' => 'WORK' + ] + ] + ] + )->getId(); + $userId = $this->mainService->getCurrentUserProfile()->getUserProfile()->ID; + $registerCallResult = $this->externalCallService->registerCall([ + 'USER_PHONE_INNER' => '14', + 'USER_ID' => $userId, + 'PHONE_NUMBER' => $phoneNumber, + 'CALL_START_DATE' => $callStartDate, + 'CRM_CREATE' => 0, + 'CRM_SOURCE' => '1', + 'CRM_ENTITY_TYPE' => (string)CrmEntityType::lead(), + 'CRM_ENTITY_ID' => $leadId, + 'SHOW' => 1, + 'CALL_LIST_ID' => 1, + 'LINE_NUMBER' => $phoneNumber, + 'TYPE' => (string)CallType::inboundCall(), + ])->getExternalCallRegister(); + + self::assertTrue((bool)$registerCallResult); + self::assertEquals($registerCallResult->CRM_ENTITY_ID, $leadId, sprintf('registered entity id : %s , and lead id: %s, should not differ', + $registerCallResult->CRM_ENTITY_ID, $leadId)); + } + + /** + * @throws BaseException + * @throws TransportException + * @throws Exception + * @covers ExternalCall::show + */ + + + public function testShowCallCard(): void + { + $datetime = new DateTime('now'); + $callStartDate = $datetime->format(DateTimeInterface::ATOM); + $phoneNumber = '+79788045001'; + $leadId = $this->leadService->add( + [ + 'TITLE' => 'test lead', + 'PHONE' => [ + [ + 'VALUE' => $phoneNumber, + 'VALUE_TYPE' => 'WORK' + ] + ] + ] + )->getId(); + $userId = $this->mainService->getCurrentUserProfile()->getUserProfile()->ID; + $registerCallResult = $this->externalCallService->registerCall([ + 'USER_PHONE_INNER' => '14', + 'USER_ID' => $userId, + 'PHONE_NUMBER' => $phoneNumber, + 'CALL_START_DATE' => $callStartDate, + 'CRM_CREATE' => 0, + 'CRM_SOURCE' => '1', + 'CRM_ENTITY_TYPE' => (string)CrmEntityType::lead(), + 'CRM_ENTITY_ID' => $leadId, + 'SHOW' => 0, + 'CALL_LIST_ID' => 1, + 'LINE_NUMBER' => $phoneNumber, + 'TYPE' => (string)CallType::inboundCall(), + ])->getExternalCallRegister(); + self::assertTrue($this->externalCallService->show($registerCallResult->CALL_ID, $userId)->isShown()); + } + + /** + * @throws BaseException + * @throws TransportException + * @throws Exception + * @covers ExternalCall::hide + */ + public function testHideCallCard(): void + { + $datetime = new DateTime('now'); + $callStartDate = $datetime->format(DateTimeInterface::ATOM); + $phoneNumber = '+79788045001'; + $leadId = $this->leadService->add( + [ + 'TITLE' => 'test lead', + 'PHONE' => [ + [ + 'VALUE' => $phoneNumber, + 'VALUE_TYPE' => 'WORK' + ] + ] + ] + )->getId(); + $userId = $this->mainService->getCurrentUserProfile()->getUserProfile()->ID; + $registerCallResult = $this->externalCallService->registerCall([ + 'USER_PHONE_INNER' => '14', + 'USER_ID' => $userId, + 'PHONE_NUMBER' => $phoneNumber, + 'CALL_START_DATE' => $callStartDate, + 'CRM_CREATE' => 0, + 'CRM_SOURCE' => '1', + 'CRM_ENTITY_TYPE' => (string)CrmEntityType::lead(), + 'CRM_ENTITY_ID' => $leadId, + 'SHOW' => 0, + 'CALL_LIST_ID' => 1, + 'LINE_NUMBER' => $phoneNumber, + 'TYPE' => (string)CallType::inboundCall(), + ])->getExternalCallRegister(); + self::assertTrue($this->externalCallService->hide($registerCallResult->CALL_ID, $userId)->isHided()); + } + + /** + * @throws TransportException + * @throws BaseException + * @throws Exception + * @covers ExternalCall::finish + */ + public function testFinish(): void + { + $datetime = new DateTime('now'); + $callStartDate = $datetime->format(DateTimeInterface::ATOM); + $phoneNumber = sprintf('+7%s', time()); + $leadId = $this->leadService->add( + [ + 'TITLE' => 'test lead', + 'PHONE' => [ + [ + 'VALUE' => $phoneNumber, + 'VALUE_TYPE' => 'WORK' + ] + ] + ] + )->getId(); + $userId = $this->mainService->getCurrentUserProfile()->getUserProfile()->ID; + $registerCallResult = $this->externalCallService->registerCall([ + 'USER_PHONE_INNER' => '14', + 'USER_ID' => $userId, + 'PHONE_NUMBER' => $phoneNumber, + 'CALL_START_DATE' => $callStartDate, + 'CRM_CREATE' => 0, + 'CRM_SOURCE' => '1', + 'CRM_ENTITY_TYPE' => (string)CrmEntityType::lead(), + 'CRM_ENTITY_ID' => $leadId, + 'SHOW' => 1, + 'CALL_LIST_ID' => 1, + 'LINE_NUMBER' => $phoneNumber, + 'TYPE' => (string)CallType::inboundCall(), + ])->getExternalCallRegister(); + + $finishCallResult = $this->externalCallService->finish([ + 'CALL_ID' => $registerCallResult->CALL_ID, + 'USER_ID' => $userId, + 'DURATION' => 255, + 'COST' => 250, + 'COST_CURRENCY' => 'RUB', + 'STATUS_CODE' => StatusSipCodeInterface::STATUS_OK, + 'FAILED_REASON' => '', + 'RECORD_URL' => '', + 'VOTE' => 5, + 'ADD_TO_CHAT' => 1 + ])->getExternalCallFinish(); + + self::assertEquals($registerCallResult->CALL_ID, $finishCallResult->CALL_ID, sprintf('registered: %s , and finish: %s, CALL_ID do not match', + $registerCallResult->CALL_ID, $finishCallResult->CALL_ID)); + + self::assertEquals($registerCallResult->CRM_ENTITY_ID, $finishCallResult->CRM_ENTITY_ID, sprintf('registered: %s , and finish: %s, ENTITY_ID do not match', + $registerCallResult->CRM_ENTITY_ID, $finishCallResult->CRM_ENTITY_ID)); + + self::assertNotEmpty($finishCallResult->CALL_DURATION, 'call time cannot be empty'); + self::assertNotEmpty($finishCallResult->COST, 'call cost cannot be empty'); + self::assertNotEmpty($finishCallResult->CALL_STATUS, 'status code must return call code and cannot be empty'); + self::assertNotEmpty($finishCallResult->PHONE_NUMBER, 'phone number cannot be empty'); + } + + /** + * @throws TransportException + * @throws BaseException + * @throws Exception + * @covers ExternalCall::attachRecord + */ + public function testAttachRecord(): void + { + $datetime = new DateTime('now'); + $callStartDate = $datetime->format(DateTimeInterface::ATOM); + $phoneNumber = sprintf('+7%s', time()); + $leadId = $this->leadService->add( + [ + 'TITLE' => 'test lead', + 'PHONE' => [ + [ + 'VALUE' => $phoneNumber, + 'VALUE_TYPE' => 'WORK' + ] + ] + ] + )->getId(); + $userId = $this->mainService->getCurrentUserProfile()->getUserProfile()->ID; + $registerCallResult = $this->externalCallService->registerCall([ + 'USER_PHONE_INNER' => '14', + 'USER_ID' => $userId, + 'PHONE_NUMBER' => $phoneNumber, + 'CALL_START_DATE' => $callStartDate, + 'CRM_CREATE' => 0, + 'CRM_SOURCE' => '1', + 'CRM_ENTITY_TYPE' => (string)CrmEntityType::lead(), + 'CRM_ENTITY_ID' => $leadId, + 'SHOW' => 1, + 'CALL_LIST_ID' => 1, + 'LINE_NUMBER' => $phoneNumber, + 'TYPE' => (string)CallType::inboundCall(), + ])->getExternalCallRegister(); + + $finishCallResult = $this->externalCallService->finish([ + 'CALL_ID' => $registerCallResult->CALL_ID, + 'USER_ID' => $userId, + 'DURATION' => 10, + 'COST' => 250, + 'COST_CURRENCY' => 'RUB', + 'STATUS_CODE' => StatusSipCodeInterface::STATUS_OK, + 'FAILED_REASON' => '', + 'RECORD_URL' => '', + 'VOTE' => 5, + 'ADD_TO_CHAT' => 1 + ])->getExternalCallFinish(); + + $fileName = sprintf('test%s.mp3', time()); + self::assertGreaterThan(1, $this->externalCallService->attachRecord($registerCallResult->CALL_ID, $fileName, $this->getFileInBase64())->getFileId()); + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public function setUp(): void + { + $this->externalCallService = Fabric::getServiceBuilder()->getTelephonyScope()->externalCall(); + $this->leadService = Fabric::getServiceBuilder()->getCRMScope()->lead(); + $this->mainService = Fabric::getServiceBuilder()->getMainScope()->main(); + } + + + private function getFileInBase64(): string + { + $filePath = __DIR__ . '/assets/'; + $fileName = 'test-phone-record.mp3'; + $resBase64 = ''; + $handle = fopen($filePath . $fileName, "rb"); + if ($handle) { + $buffer = fread($handle, filesize($filePath . $fileName)); + $resBase64 = base64_encode($buffer); + } + fclose($handle); + + return $resBase64; + } +} \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/Service/ExternalLineTest.php b/tests/Integration/Services/Telephony/Service/ExternalLineTest.php new file mode 100644 index 00000000..d8320432 --- /dev/null +++ b/tests/Integration/Services/Telephony/Service/ExternalLineTest.php @@ -0,0 +1,110 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Tests\Integration\Services\Telephony\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\Telephony\Service\ExternalLine; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\TestCase; + +class ExternalLineTest extends TestCase +{ + protected ExternalLine $externalLineService; + + /** + * @throws BaseException + * @throws TransportException + * @covers ExternalLine::add + */ + public function testAdd(): void + { + self::assertGreaterThan(1, $this->externalLineService->add((string)time(), sprintf('phpUnit-%s', time()))->getId()); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers ExternalLine::get + */ + public function testGet(): void + { + $this->externalLineService->add((string)time(), sprintf('phpUnit-%s', time())); + $this->externalLineService->add((string)time(), sprintf('phpUnit-%s', time())); + self::assertGreaterThanOrEqual(2, $this->externalLineService->get()->getExternalLines()); + } + + /** + * @throws BaseException + * @throws TransportException + * @throws \Exception + * @covers ExternalLine::update + */ + public function testUpdateExternalLineName(): void + { + $lineNumber = $this->getRandomLineNumber(); + $lineNameBefore = sprintf('phpUnit-%s-name-before', time()); + + $externalLineId = $this->externalLineService->add($lineNumber, $lineNameBefore)->getId(); + + + $lineNameAfter = sprintf('phpUnit-%s-name-after', time()); + $updatedLineId = $this->externalLineService->update($lineNumber, $lineNameAfter)->updateExternalLineId(); + $this->assertEquals($externalLineId, $updatedLineId, sprintf('external line id %s not equals with %s', + $externalLineId, + $updatedLineId + )); + + $externalLineNameAfter = array_column($this->externalLineService->get()->getExternalLines(), 'NAME'); + self::assertFalse(in_array($lineNameBefore, $externalLineNameAfter), + sprintf('expected update line name «%s» line name see %s name', $lineNameBefore, $lineNameAfter)); + } + + /** + * @throws BaseException + * @throws TransportException + * @throws \Exception + * @covers ExternalLine::delete + */ + public function testDelete(): void + { + $lineNumber = $this->getRandomLineNumber(); + + self::assertGreaterThan(1, $this->externalLineService->add($lineNumber, sprintf('phpUnit-%s', time()))->getId()); + $externalLineNumbersBefore = array_column($this->externalLineService->get()->getExternalLines(), 'NUMBER'); + + $this->externalLineService->delete($lineNumber); + $externalLineNumbersAfter = array_column($this->externalLineService->get()->getExternalLines(), 'NUMBER'); + + $deletedLineNumber = array_values(array_diff($externalLineNumbersBefore, $externalLineNumbersAfter))[0]; + self::assertEquals($lineNumber, $deletedLineNumber, sprintf('expected deleted %s number see %s number', $lineNumber, $deletedLineNumber)); + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public function setUp(): void + { + $this->externalLineService = Fabric::getServiceBuilder()->getTelephonyScope()->externalline(); + } + + /** + * @return string + * @throws \Exception + */ + private function getRandomLineNumber(): string + { + return (string)time() . (string)random_int(1, PHP_INT_MAX); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php b/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php new file mode 100644 index 00000000..91365b68 --- /dev/null +++ b/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php @@ -0,0 +1,201 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Tests\Integration\Services\Telephony\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\CRM\Contact\Service\Contact; +use Bitrix24\SDK\Services\CRM\Lead\Service\Lead; +use Bitrix24\SDK\Services\Telephony\Service\ExternalCall; +use Bitrix24\SDK\Tests\Integration\Fabric; +use Exception; +use PHPUnit\Framework\TestCase; + +class SearchCrmEntitiesTest extends TestCase +{ + + protected Lead $leadService; + protected ExternalCall $externalCallService; + protected Contact $contactService; + + /** + * @throws Exception + * @covers ExternalCall::searchCrmEntities + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function testSearchCrmEntitiesWithEmptyResult(): void + { + //Не зарегистрированный телефон + $unusedPhone = '+51045005010'; + $infoAboutNotExistingCustomerResult = $this->externalCallService->searchCrmEntities($unusedPhone)->getCrmEntitiesSearchResult(); + self::assertEmpty($infoAboutNotExistingCustomerResult, sprintf('No customers can be found for this number: %s', $unusedPhone)); + } + + /** + * @throws Exception + * @covers ExternalCall::searchCrmEntities + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function testSearchCrmEntitiesContactFound(): void + { + //Зарегистрированный контакт + $phoneNumberClient = sprintf('+7%s%s', time(), random_int(1, PHP_INT_MAX)); + $contactId = $this->contactService->add( + [ + 'NAME' => 'Глеб', + 'SECOND_NAME' => 'Егорович', + 'PHONE' => [ + [ + 'VALUE' => $phoneNumberClient, + 'VALUE_TYPE' => 'WORK', + ], + ], + ] + )->getId(); + $infoAboutClientResult = $this->externalCallService->searchCrmEntities($phoneNumberClient)->getCrmEntitiesSearchResult(); + $this->assertCount(1, $infoAboutClientResult); + + self::assertEquals( + 'CONTACT', + $infoAboutClientResult[0]->CRM_ENTITY_TYPE, + sprintf( + 'name type incorrect, expected: CONTACT , and your type: %s', + $infoAboutClientResult[0]->CRM_ENTITY_TYPE + ) + ); + + $this->assertEquals($contactId, $infoAboutClientResult[0]->CRM_ENTITY_ID); + + $this->contactService->delete($contactId); + } + + /** + * @throws TransportException + * @throws BaseException + * @throws Exception + * @covers ExternalCall::searchCrmEntities + */ + public function testSearchCrmEntitiesLeadFound(): void + { + //Зарегистрированный лид + $phoneNumberLead = sprintf('+7%s%s', time(), random_int(1, PHP_INT_MAX)); + $leadId1 = $this->leadService->add( + [ + 'TITLE' => 'ИП Титов', + 'NAME' => 'Кирилл', + 'PHONE' => [ + [ + 'VALUE' => $phoneNumberLead, + 'VALUE_TYPE' => 'WORK', + ], + ], + ] + )->getId(); + $infoAboutLeadResult = $this->externalCallService->searchCrmEntities($phoneNumberLead)->getCrmEntitiesSearchResult(); + $this->assertCount(1, $infoAboutLeadResult); + + self::assertEquals( + 'LEAD', + $infoAboutLeadResult[0]->CRM_ENTITY_TYPE, + sprintf('name type incorrect, expected: LEAD , and your type: %s', $infoAboutLeadResult[0]->CRM_ENTITY_TYPE) + ); + $this->leadService->delete($leadId1); + } + + /** + * @throws TransportException + * @throws BaseException + * @throws Exception + * @covers ExternalCall::searchCrmEntities + */ + public function testSearchCrmEntitiesMultipleContactsFound(): void + { + $contactPhone = sprintf('+7%s%s', time(), random_int(1, PHP_INT_MAX)); + $contactId1 = $this->contactService->add( + [ + 'NAME' => 'Глеб', + 'SECOND_NAME' => 'Егорович', + 'PHONE' => [ + [ + 'VALUE' => $contactPhone, + 'VALUE_TYPE' => 'WORK', + ], + ], + ] + )->getId(); + $contactId2 = $this->contactService->add( + [ + 'NAME' => 'Хлеб', + 'SECOND_NAME' => 'Олегович', + 'PHONE' => [ + [ + 'VALUE' => $contactPhone, + 'VALUE_TYPE' => 'WORK', + ], + ], + ] + )->getId(); + $contactIds = [$contactId1, $contactId2]; + $this->externalCallService->searchCrmEntities($contactPhone)->getCrmEntitiesSearchResult(); + $this->assertTrue(in_array($contactId1, $contactIds, true)); + $this->contactService->delete($contactId1); + $this->contactService->delete($contactId2); + } + + /** + * @throws Exception + * @covers ExternalCall::searchCrmEntities + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function testSearchCrmEntitiesWithDifferentPhonePrefix(): void + { + $phoneBody = sprintf('+7%s%s', time(), random_int(1, PHP_INT_MAX)); + $contactPhone1 = sprintf('+7%s', $phoneBody); + $contactPhone2 = sprintf('+8%s', $phoneBody); + $contactId1 = $this->contactService->add( + [ + 'NAME' => 'Глеб', + 'SECOND_NAME' => 'Егорович', + 'PHONE' => [ + [ + 'VALUE' => $contactPhone1, + 'VALUE_TYPE' => 'WORK', + ], + ], + ] + )->getId(); + + $infoAboutTwoContactsResult1 = $this->externalCallService->searchCrmEntities($contactPhone1)->getCrmEntitiesSearchResult(); + $infoAboutTwoContactsResult2 = $this->externalCallService->searchCrmEntities($contactPhone2)->getCrmEntitiesSearchResult(); + $infoAboutTwoContactsResult3 = $this->externalCallService->searchCrmEntities($phoneBody)->getCrmEntitiesSearchResult(); + $this->assertEquals($contactId1, $infoAboutTwoContactsResult1[0]->CRM_ENTITY_ID); + $this->assertEmpty($infoAboutTwoContactsResult2); + $this->assertEmpty($infoAboutTwoContactsResult3); + $this->contactService->delete($contactId1); + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public function setUp(): void + { + $this->externalCallService = Fabric::getServiceBuilder()->getTelephonyScope()->externalCall(); + $this->leadService = Fabric::getServiceBuilder()->getCRMScope()->lead(); + $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); + } + +} \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/Service/assets/test-phone-record.mp3 b/tests/Integration/Services/Telephony/Service/assets/test-phone-record.mp3 new file mode 100644 index 00000000..ad8f9738 Binary files /dev/null and b/tests/Integration/Services/Telephony/Service/assets/test-phone-record.mp3 differ diff --git a/tests/Integration/Services/UserConsent/Service/UserConsentAgreementTest.php b/tests/Integration/Services/UserConsent/Service/UserConsentAgreementTest.php new file mode 100644 index 00000000..3f694869 --- /dev/null +++ b/tests/Integration/Services/UserConsent/Service/UserConsentAgreementTest.php @@ -0,0 +1,58 @@ +assertIsArray($this->userConsentAgreementService->list()->getAgreements()); + } + + /** + * @covers UserConsentAgreement::text + * @testdox test get agreements list + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function testText(): void + { + // get agreement id + $agreements = $this->userConsentAgreementService->list()->getAgreements(); + // empty agreement list + if (count($agreements) === 0) { + $this->assertTrue(true); + + return; + } + $agreementId = $agreements[0]->ID; + $agreementText = $this->userConsentAgreementService->text($agreementId, [ + 'button_caption' => 'Button call to action title', + 'fields' => 'fields collection: email, phone', + ])->text(); + + $this->assertNotNull($agreementText->TEXT); + $this->assertNotNull($agreementText->LABEL); + } + + public function setUp(): void + { + $this->userConsentAgreementService = Fabric::getServiceBuilder()->getUserConsentScope()->UserConsentAgreement(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/UserConsent/Service/UserConsentTest.php b/tests/Integration/Services/UserConsent/Service/UserConsentTest.php new file mode 100644 index 00000000..7759a6a2 --- /dev/null +++ b/tests/Integration/Services/UserConsent/Service/UserConsentTest.php @@ -0,0 +1,52 @@ +userConsentAgreementService->list()->getAgreements(); + // empty agreement list + if (count($agreements) === 0) { + $this->assertTrue(true); + + return; + } + + $agreementId = $agreements[0]->ID; + $res = $this->userConsentService->add( + [ + 'agreement_id' => $agreementId, + 'ip' => '127.0.0.1', + 'origin_id' => 'offline', + 'originator_id' => 'test@gmail.com', + ] + ); + $this->assertIsInt($res->getId()); + } + + public function setUp(): void + { + $this->userConsentService = Fabric::getServiceBuilder()->getUserConsentScope()->UserConsent(); + $this->userConsentAgreementService = Fabric::getServiceBuilder()->getUserConsentScope()->UserConsentAgreement(); + } +} \ No newline at end of file diff --git a/tests/Unit/Application/ApplicationStatusTest.php b/tests/Unit/Application/ApplicationStatusTest.php new file mode 100644 index 00000000..cdf70fb6 --- /dev/null +++ b/tests/Unit/Application/ApplicationStatusTest.php @@ -0,0 +1,70 @@ +assertEquals( + $longCode, + (new ApplicationStatus($shortCode))->getStatusCode() + ); + } + + /** + * @return void + */ + public function testInvalidStatusCode(): void + { + $this->expectException(InvalidArgumentException::class); + new ApplicationStatus('foo'); + } + + /** + * @return \Generator + */ + public function statusDataProvider(): Generator + { + yield 'free' => [ + 'F', + 'free', + ]; + + yield 'demo' => [ + 'D', + 'demo', + ]; + yield 'trial' => [ + 'T', + 'trial', + ]; + yield 'paid' => [ + 'P', + 'paid', + ]; + yield 'local' => [ + 'L', + 'local', + ]; + yield 'subscription' => [ + 'S', + 'subscription', + ]; + } +} \ No newline at end of file diff --git a/tests/Unit/Core/CoreBuilderTest.php b/tests/Unit/Core/CoreBuilderTest.php new file mode 100644 index 00000000..33ffa331 --- /dev/null +++ b/tests/Unit/Core/CoreBuilderTest.php @@ -0,0 +1,39 @@ +withCredentials(Credentials::createFromWebhook(new WebhookUrl('https://127.0.0.1'))) + ->build(); + // successful build core + $this->assertTrue(true); + } + + /** + * @throws UnknownScopeCodeException + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public function testBuildWithoutCredentials(): void + { + $this->expectException(InvalidArgumentException::class); + $core = (new CoreBuilder()) + ->build(); + } +} diff --git a/tests/Unit/Core/Credentials/ApplicationProfileTest.php b/tests/Unit/Core/Credentials/ApplicationProfileTest.php new file mode 100644 index 00000000..a66a38ce --- /dev/null +++ b/tests/Unit/Core/Credentials/ApplicationProfileTest.php @@ -0,0 +1,69 @@ +expectException($expectedException); + } + $prof = ApplicationProfile::initFromArray($arr); + + $this->assertEquals($prof->getClientId(), $arr['BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID']); + $this->assertEquals($prof->getClientSecret(), $arr['BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET']); + } + + public function arrayDataProvider(): Generator + { + yield 'valid' => [ + [ + 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID' => '1', + 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET' => '2', + 'BITRIX24_PHP_SDK_APPLICATION_SCOPE' => 'user', + ], + null, + ]; + yield 'without client id' => [ + [ + '' => '1', + 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET' => '2', + 'BITRIX24_PHP_SDK_APPLICATION_SCOPE' => 'user', + ], + InvalidArgumentException::class, + ]; + yield 'without client secret' => [ + [ + 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID' => '1', + '' => '2', + 'BITRIX24_PHP_SDK_APPLICATION_SCOPE' => 'user', + ], + InvalidArgumentException::class, + ]; + yield 'without client application scope' => [ + [ + 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID' => '1', + 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET' => '2', + '' => 'user', + ], + InvalidArgumentException::class, + ]; + } +} diff --git a/tests/Unit/Core/Credentials/CredentialsTest.php b/tests/Unit/Core/Credentials/CredentialsTest.php new file mode 100644 index 00000000..5d3ccfdb --- /dev/null +++ b/tests/Unit/Core/Credentials/CredentialsTest.php @@ -0,0 +1,96 @@ +assertEquals($expectedDomainUrl, $credentials->getDomainUrl()); + } + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws \Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException + */ + public function testDomainUrlWithoutProtocol(): void + { + $credentials = Credentials::createFromOAuth( + new AccessToken('', '', 0), + new ApplicationProfile('', '', new Scope(['crm'])), + 'bitrix24-php-sdk-playground.bitrix24.ru' + ); + $this->assertEquals( + 'https://bitrix24-php-sdk-playground.bitrix24.ru', + $credentials->getDomainUrl() + ); + } + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws \Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException + */ + public function testDomainUrlWithProtocol(): void + { + $credentials = Credentials::createFromOAuth( + new AccessToken('', '', 0), + new ApplicationProfile('', '', new Scope(['crm'])), + 'https://bitrix24-php-sdk-playground.bitrix24.ru' + ); + $this->assertEquals( + 'https://bitrix24-php-sdk-playground.bitrix24.ru', + $credentials->getDomainUrl() + ); + } + + /** + * @return \Generator + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws \Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException + */ + public function credentialsDataProviderWithDomainUrlVariants(): Generator + { + yield 'with webhook walid domain url' => [ + Credentials::createFromWebhook(new WebhookUrl('https://bitrix24-php-sdk-playground.bitrix24.ru/rest/1/valid-webhook/')), + 'https://bitrix24-php-sdk-playground.bitrix24.ru', + ]; + yield 'with oauth domain url with end /' => [ + Credentials::createFromOAuth( + new AccessToken('', '', 0), + new ApplicationProfile('', '', new Scope(['crm'])), + 'https://bitrix24-php-sdk-playground.bitrix24.ru/' + ), + 'https://bitrix24-php-sdk-playground.bitrix24.ru', + ]; + yield 'with oauth domain url without end /' => [ + Credentials::createFromOAuth( + new AccessToken('', '', 0), + new ApplicationProfile('', '', new Scope(['crm'])), + 'https://bitrix24-php-sdk-playground.bitrix24.ru' + ), + 'https://bitrix24-php-sdk-playground.bitrix24.ru', + ]; + } +} diff --git a/tests/Unit/Core/Response/DTO/TimeTest.php b/tests/Unit/Core/Response/DTO/TimeTest.php index 46ef120b..64f597b2 100644 --- a/tests/Unit/Core/Response/DTO/TimeTest.php +++ b/tests/Unit/Core/Response/DTO/TimeTest.php @@ -5,6 +5,7 @@ namespace Bitrix24\SDK\Tests\Unit\Core\Response\DTO; use Bitrix24\SDK\Core\Response\DTO\Time; +use Generator; use PHPUnit\Framework\TestCase; /** @@ -15,26 +16,52 @@ class TimeTest extends TestCase { /** - * @throws \Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException + * @throws \Exception + * @dataProvider timingsDataProvider */ - public function testInitFromResponseData(): void + public function testInitFromResponseData(array $result): void { - $result = [ - 'start' => 1604098405.469694, - 'finish' => 1604098405.50439, - 'duration' => 0.034696102142333984, - 'processing' => 6.198883056640625E-5, - 'date_start' => '2020-10-31T01:53:25+03:00', - 'date_finish' => '2020-10-31T01:53:26+03:00', - ]; - $time = Time::initFromResponse($result); $this->assertEquals($result['start'], $time->getStart()); $this->assertEquals($result['finish'], $time->getFinish()); $this->assertEquals($result['duration'], $time->getDuration()); $this->assertEquals($result['processing'], $time->getProcessing()); + $this->assertEquals($result['operating'], $time->getOperating()); + $this->assertEquals($result['operating_reset_at'], $time->getOperatingResetAt()); $this->assertEquals($result['date_start'], $time->getDateStart()->format(\DATE_ATOM)); $this->assertEquals($result['date_finish'], $time->getDateFinish()->format(\DATE_ATOM)); } + + /** + * @return \Generator + */ + public function timingsDataProvider(): Generator + { + yield 'without operating reset at' => [ + [ + 'start' => 1604098405.469694, + 'finish' => 1604098405.50439, + 'duration' => 0.034696102142333984, + 'processing' => 6.198883056640625E-5, + 'operating' => 0.11336898803710938, + 'operating_reset_at' => null, + 'date_start' => '2020-10-31T01:53:25+03:00', + 'date_finish' => '2020-10-31T01:53:26+03:00', + ], + ]; + + yield 'with operating reset at' => [ + [ + 'start' => 1604098405.469694, + 'finish' => 1604098405.50439, + 'duration' => 0.034696102142333984, + 'processing' => 6.198883056640625E-5, + 'operating' => 0.11336898803710938, + 'operating_reset_at' => 20, + 'date_start' => '2020-10-31T01:53:25+03:00', + 'date_finish' => '2020-10-31T01:53:26+03:00', + ], + ]; + } } diff --git a/tests/Unit/Stubs/NullBatch.php b/tests/Unit/Stubs/NullBatch.php index efd8ab43..14ddbb6f 100644 --- a/tests/Unit/Stubs/NullBatch.php +++ b/tests/Unit/Stubs/NullBatch.php @@ -5,6 +5,8 @@ namespace Bitrix24\SDK\Tests\Unit\Stubs; use Bitrix24\SDK\Core\Contracts\BatchInterface; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Response\DTO\ResponseData; use Generator; /** @@ -51,4 +53,12 @@ public function deleteEntityItems(string $apiMethod, array $entityItemId): Gener { yield []; } + + /** + * @inheritDoc + */ + public function updateEntityItems(string $apiMethod, array $entityItems): Generator + { + yield []; + } } \ No newline at end of file diff --git a/tests/Unit/Stubs/NullCore.php b/tests/Unit/Stubs/NullCore.php index 494c0c3e..493da934 100644 --- a/tests/Unit/Stubs/NullCore.php +++ b/tests/Unit/Stubs/NullCore.php @@ -36,6 +36,6 @@ public function call(string $apiMethod, array $parameters = []): Response public function getApiClient(): ApiClientInterface { - return new ApiClient(Credentials::createForWebHook(new WebhookUrl('')), new MockHttpClient(), new NullLogger()); + return new ApiClient(Credentials::createFromWebhook(new WebhookUrl('')), new MockHttpClient(), new NullLogger()); } } \ No newline at end of file diff --git a/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php b/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php index 1a37e3a9..baaa96b4 100644 --- a/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php +++ b/tools/DemoDataGenerators/CRM/Contacts/GenerateContactsCommand.php @@ -7,6 +7,8 @@ use Bitrix24\SDK\Core\Batch; use Bitrix24\SDK\Core\BulkItemsReader\BulkItemsReaderBuilder; use Bitrix24\SDK\Core\CoreBuilder; +use Bitrix24\SDK\Core\Credentials\Credentials; +use Bitrix24\SDK\Core\Credentials\WebhookUrl; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Services\ServiceBuilder; use InvalidArgumentException; @@ -114,7 +116,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int // todo create service builder factory $core = (new CoreBuilder()) ->withLogger($this->logger) - ->withWebhookUrl($b24Webhook) + ->withCredentials(Credentials::createFromWebhook(new WebhookUrl($b24Webhook))) ->build(); $batch = new Batch( $core, diff --git a/tools/PerformanceBenchmarks/ListCommand.php b/tools/PerformanceBenchmarks/ListCommand.php index 309d98fc..1a5d06f7 100644 --- a/tools/PerformanceBenchmarks/ListCommand.php +++ b/tools/PerformanceBenchmarks/ListCommand.php @@ -8,6 +8,8 @@ use Bitrix24\SDK\Core\Contracts\BatchInterface; use Bitrix24\SDK\Core\Contracts\CoreInterface; use Bitrix24\SDK\Core\CoreBuilder; +use Bitrix24\SDK\Core\Credentials\Credentials; +use Bitrix24\SDK\Core\Credentials\WebhookUrl; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Exceptions\TransportException; use Psr\Log\LoggerInterface; @@ -147,7 +149,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->core = (new CoreBuilder()) ->withLogger($this->logger) - ->withWebhookUrl($b24Webhook) + ->withCredentials(Credentials::createFromWebhook(new WebhookUrl($b24Webhook))) ->build(); $this->batch = new Batch( $this->core, diff --git a/tools/ShowFieldsDescriptionCommand.php b/tools/ShowFieldsDescriptionCommand.php index fd23ea2e..af6254c9 100644 --- a/tools/ShowFieldsDescriptionCommand.php +++ b/tools/ShowFieldsDescriptionCommand.php @@ -5,6 +5,9 @@ namespace Bitrix24\SDK\Tools; use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\CoreBuilder; +use Bitrix24\SDK\Core\Credentials\Credentials; +use Bitrix24\SDK\Core\Credentials\WebhookUrl; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Response\Response; use Psr\Log\LoggerInterface; @@ -80,12 +83,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int $io = new SymfonyStyle($input, $output); try { - $this->core = (new \Bitrix24\SDK\Core\CoreBuilder()) + $this->core = (new CoreBuilder()) ->withLogger($this->logger) - ->withWebhookUrl($b24Webhook) + ->withCredentials(Credentials::createFromWebhook(new WebhookUrl($b24Webhook))) ->build(); - $methods = $this->core->call('methods', ['full' => true])->getResponseData()->getResult()->getResultData(); + $methods = $this->core->call('methods', ['full' => true])->getResponseData()->getResult(); $fieldsMethods = []; foreach ($methods as $method) { if (strpos($method, 'fields') !== false) { @@ -164,7 +167,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int private function showFieldsAsPhpDocFunctionSelectSuggest(OutputInterface $output, Response $fields): void { $fieldsList = []; - foreach ($fields->getResponseData()->getResult()->getResultData() as $fieldCode => $fieldDescription) { + foreach ($fields->getResponseData()->getResult() as $fieldCode => $fieldDescription) { $fieldsList[] = sprintf("'%s'", $fieldCode); } $output->writeln(' * @param array $select = [' . implode(',', $fieldsList) . ']'); @@ -179,7 +182,7 @@ private function showFieldsAsPhpDocFunctionSelectSuggest(OutputInterface $output private function showFieldsAsPhpDocFunctionProperty(OutputInterface $output, Response $fields): void { $fieldsList = ['*', '* @param array{']; - foreach ($fields->getResponseData()->getResult()->getResultData() as $fieldCode => $fieldDescription) { + foreach ($fields->getResponseData()->getResult() as $fieldCode => $fieldDescription) { switch (strtolower($fieldDescription['type'])) { case 'integer': $phpDocType = 'int'; @@ -206,7 +209,7 @@ private function showFieldsAsPhpDocFunctionProperty(OutputInterface $output, Res private function showFieldsAsPhpDocClassHeader(OutputInterface $output, Response $fields): void { $fieldsList = ['/**', '*']; - foreach ($fields->getResponseData()->getResult()->getResultData() as $fieldCode => $fieldDescription) { + foreach ($fields->getResponseData()->getResult() as $fieldCode => $fieldDescription) { switch (strtolower($fieldDescription['type'])) { case 'integer': $phpDocType = 'int'; @@ -233,7 +236,7 @@ private function showFieldsAsTable(OutputInterface $output, Response $fields): v { $fieldsTable = []; // some methods return description in upper case - $fields = array_change_key_case($fields->getResponseData()->getResult()->getResultData(), CASE_LOWER); + $fields = array_change_key_case($fields->getResponseData()->getResult(), CASE_LOWER); foreach ($fields as $fieldCode => $fieldDescription) { $fieldDescription = array_change_key_case($fieldDescription, CASE_LOWER);