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/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml new file mode 100644 index 00000000..64ea73b4 --- /dev/null +++ b/.github/workflows/phpstan.yml @@ -0,0 +1,52 @@ +on: + push: + pull_request: + +name: PHPStan checks + +jobs: + static-analysis: + name: "PHPStan" + runs-on: ${{ matrix.operating-system }} + + strategy: + fail-fast: false + matrix: + php-version: + - "8.2" + - "8.3" + dependencies: [ highest ] + operating-system: [ ubuntu-latest, windows-latest ] + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "none" + php-version: "${{ matrix.php-version }}" + extensions: json, bcmath, curl, intl, mbstring + tools: composer:v2 + + - name: "Install lowest dependencies" + if: ${{ matrix.dependencies == 'lowest' }} + run: "composer update --prefer-lowest --no-interaction --no-progress --no-suggest" + + - name: "Install highest dependencies" + if: ${{ matrix.dependencies == 'highest' }} + run: "composer update --no-interaction --no-progress --no-suggest" + + - name: "PHPStan" + run: "composer phpstan-analyse" + + - name: "is PHPStan check succeeded" + if: ${{ success() }} + run: | + echo '✅ PHPStan check pass, congratulations!' + + - name: "is PHPStan check failed" + if: ${{ failure() }} + run: | + echo '::error:: ❗️ PHPStan check failed (╯°益°)╯彡┻━┻' \ No newline at end of file diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml new file mode 100644 index 00000000..00dc1d47 --- /dev/null +++ b/.github/workflows/phpunit.yml @@ -0,0 +1,51 @@ +name: "PHPUnit tests" + +on: + push: + pull_request: + +env: + COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist" + +jobs: + tests: + name: "PHPUnit tests" + + runs-on: ${{ matrix.operating-system }} + + strategy: + fail-fast: false + matrix: + php-version: + - "8.2" + - "8.3" + dependencies: [ highest ] + operating-system: [ ubuntu-latest, windows-latest ] + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "none" + php-version: "${{ matrix.php-version }}" + extensions: json, bcmath, curl, intl, mbstring + + - name: "Install dependencies" + run: | + composer update ${{ env.COMPOSER_FLAGS }} + + - name: "run unit tests" + run: "composer phpunit-run-unit-tests" + + - name: "is unit tests tests succeeded" + if: ${{ success() }} + run: | + echo '✅ unit tests pass, congratulations!' + + - name: "is unit tests tests failed" + if: ${{ failure() }} + run: | + echo '::error:: ❗️ unit tests tests failed (╯°益°)╯彡┻━┻' \ No newline at end of file diff --git a/.github/workflows/vendor-check.yml b/.github/workflows/vendor-check.yml new file mode 100644 index 00000000..74662014 --- /dev/null +++ b/.github/workflows/vendor-check.yml @@ -0,0 +1,61 @@ +name: "Vendor integration tests" + +on: + # run integration tests from vendor CI\CD pipeline with webhook + repository_dispatch: + types: [ run_vendor_integration_tests ] + +env: + COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist" + BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK: ${{ secrets.BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK }} + +jobs: + tests: + name: "Vendor integration tests" + + runs-on: ${{ matrix.operating-system }} + + strategy: + matrix: + php-version: + - "8.2" + - "8.3" + dependencies: [ highest ] + operating-system: [ ubuntu-latest, windows-latest ] + + steps: + + - name: "Checkout" + uses: "actions/checkout@v2" + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "none" + php-version: "${{ matrix.php-version }}" + ini-values: variables_order=EGPCS + env: + BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK: ${{ secrets.BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK }} + TEST2_ENV: 12345 + + - name: "Install dependencies" + run: | + composer update ${{ env.COMPOSER_FLAGS }} + + - name: "Debug ENV variables" + run: | + printenv + + - name: "Run integration tests" + run: | + composer phpunit-run-integration-tests + + - name: "integration tests succeeded" + if: ${{ success() }} + run: | + echo '✅ integration tests pass, congratulations!' + + - name: "integration tests failed" + if: ${{ failure() }} + run: | + echo '::error:: ❗integration tests failed (╯°益°)╯彡┻━┻' \ No newline at end of file diff --git a/.gitignore b/.gitignore index 84873cd7..8f9344f1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,12 @@ /.idea* +/app vendor composer.phar -composer.lock \ No newline at end of file +composer.lock +.phpunit.result.cache +tools/.env.local +tools/logs +tests/ApplicationBridge/auth.json +examples/logs +*.log +.env.local \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index e512dcfa..00000000 --- a/.travis.yml +++ /dev/null @@ -1,28 +0,0 @@ -language: php - -php: - - 5.3.3 - - 5.4 - - 5.5 - - 5.6 - - 7.0 - - hhvm - -matrix: - allow_failures: - - php: 5.3.3 - - php: hhvm - -sudo: false - -cache: - directories: - - vendor - - $HOME/.composer/cache - -before_script: - - composer self-update - - composer install --no-interaction --prefer-source --dev - -script: - composer test diff --git a/CHANGELOG.md b/CHANGELOG.md index 829d6230..0c9a7ca9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,511 @@ # bitrix24-php-sdk change log + +## 2.0 — 28.08.2024 +* bump sdk version + +## 2.0-beta.3 — 15.08.2024 + +### Added + +* add dependencies + * `symfony/console` version `^6 || ^7` + * `symfony/dotenv` version `^6 || ^7` + * `symfony/filesystem` version `^6 || ^7` + * `symfony/mime` version `^6 || ^7` + * `nesbot/carbon` version `3.3.*` + * `mesilov/moneyphp-percentage` version `0.2.*` +* add scope `bizproc` and [services](https://github.com/mesilov/bitrix24-php-sdk/issues/376) for work with workflows: + * `Activity` – service for work with application activities: + * `add` – adds new activity to a workflow + * `delete` – delete an activity + * `list` – returns list of activities, installed by the application + * `log` – records data in the workflow log + * `update` – update activity fields + * `Robot` – service for work with application automation rules (robots): + * `add` – registers new automation rule + * `delete` – deletes registered automation rule + * `list` – returns list of automation rules, registered by the application + * `update` – updates fields of automation rules + * `Event` – service for work with return parameters¨ + * `send` – Returns the output parameters to the activity + * `Providers` — deprecated methods, not implemented + * `Workflow` — service for work with workflow instances + * `instances` – returns list of launched workflows + * `kill` – delete a launched workflow + * `start` – launches a workflow + * `terminate` – stops an active workflow + * `Template` — service for work with workflow templates + * `add` – add a workflow template + * `delete` – delete workflow template + * `list` – returns list of workflow templates + * `update` – update workflow template + * `Tasks` — service for work with workflow tasks + * `complete` – Complete workflow task + * `list` – List of workflow tasks + * add `WorkflowActivityDocumentType` +* add method `Bitrix24\SDK\Core\Credentials\AccessToken::initFromWorkflowRequest` +* add method `Bitrix24\SDK\Core\Credentials\AccessToken::initFromEventRequest` +* add `Bitrix24\SDK\Infrastructure\Filesystem\Base64Encoder` for work with base64 encoding +* add `Bitrix24\SDK\Core\Exceptions\FileNotFoundException` if file not found +* add `Bitrix24\SDK\Core\Exceptions\MethodConfirmWaitingException` if api call waiting for confirm +* add `Bitrix24\SDK\Core\Exceptions\UserNotFoundOrIsNotActiveException` exception if user not found, or it is not active +* add `Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult` result of call UI +* add `Bitrix24\SDK\Core\Result\EmptyResult` empty result +* add `IncomingRobotRequest` wrapper for data from crm-robot request +* add `IncomingWorkflowRequest` wrapper for data from biz proc activity request +* add `Bitrix24\SDK\Core\Credentials::isWebhookContext` - for check is current context init from webhook +* add method `Bitrix24\SDK\Application\Requests\Events\AbstractEventRequest::getEventId` - for get event id +* add method `Bitrix24\SDK\Application\Requests\Events\AbstractEventRequest::getAuth` - get event auth token +* add method `Bitrix24\SDK\Application\Requests\Events\EventAuthItem` - event auth token +* add method `Bitrix24\SDK\Application\Requests\Events\EventInterface` - for event fabrics +* add method `Bitrix24\SDK\Infrastructure\Filesystem\Base64Encoder::encodeCallRecord(string $filename): string` - for + work with call records +* add class `Bitrix24\SDK\Services\Main\Service\EventManager` - improve DX for work with events lifecycle bind or unbind +* add method `Bitrix24\SDK\Services\Main\Common\EventHandlerMetadata` - improve DX for work with install events +* add enum `Bitrix24\SDK\Services\CRM\Common\Result\DiscountType` +* add exception `Bitrix24\SDK\Core\Exceptions\WrongAuthTypeException` – if you use wrong auth type. +* add class fields filter `Bitrix24\SDK\Core\Fields\FieldsFilter` for fields filtration in result array. +* improve DX – add [Rector](https://github.com/rectorphp/rector) for improve code quality and speed up releases cycle +* improve DX – add attributes for generate documentation and calculate methods coverage. + * command for generate documentation +```shell + php bin/console b24:util:generate-coverage-documentation +``` +* improve DX – add [internal documentation](/docs/EN/documentation.md). + +### Changed + +* ❗️ migrate from `ramsey/uuid` to `symfony/uid` +* ❗️ migrate from `DateTimeImmutable` to `CarbonImmutable` from [carbon](https://github.com/briannesbitt/carbon) +* ❗️ refactor `Bitrix24\SDK\Application\Contracts`: + +* ❗️ update scope `telephony`, scope fully rewritten + * `ExternalCall` – work with external call: + * `getCallRecordUploadUrl` – get url for upload call record file + * `attachCallRecordInBase64` – attach call record encoded in base64 + * `register` – registers a call in Bitrix24 + * `searchCrmEntities` – retrieve information about a client from CRM by a telephone number via single request + * `finishForUserPhoneInner` – completes the call, registers it in the statistics and hides the call ID screen + from the user + * `finishForUserId` – completes the call, registers it in the statistics and hides the call ID screen from the + user + * `show` – displays a call ID screen to the user + * `hide` – hides call information window + * `Call` – work with call: + * `attachTranscription` – method adds a call transcript + * `ExternalLine` – work with external line: + * `add` – method adds an external line + * `delete` – method delete external line + * `get` – method gets external lines list + * `Voximplant` – work with voximplant namespace: + * `Sip` – work with sip lines: + * `get` - get sip lines list + * `add` - add new sip line + * `delete` - delete sip line + * `status` - pbx sip line registration status + * `update` - update sip line settings + * `getConnectorStatus` - returns the current status of the SIP Connector. + * `User` - work with voximplant sip user mapped on bitrix24 user + * `deactivatePhone` - method disables an indicator of SIP-phone availability + * `activatePhone` - method raises the event of SIP-phone availability for an employee + * `get` - method returns user settings + * `Voices` - work with voximplant tts voices + * `get` - method returns all voximplant voices + * `Line` - work with voximplant sip lines + * `outgoingSipSet` - method sets the selected SIP line as an outgoing line by default. + * `get` - returns list of all of the available outgoing lines + * `outgoingGet` - returns the currently selected line as an outgoing line by default. + * `outgoingSet` - sets the selected line as an outgoing line by default. + * `InfoCall` - work with voximplant info call functional + * `startWithText` - method performs the call to the specified number with automatic voiceover of + specified + text + * `startWithSound` - method makes a call to the specified number with playback of .mp3 format file by + URL. + * `Url` - work with links for browsing telephony scope pages + * `get` - returns a set of links for browsing telephony scope pages. + * add events with payload and `TelephonyEventsFabric`: + * `OnExternalCallBackStart` - It is called when a visitor fills out a CRM form for callback. Your application + shall be selected in the form settings as the line that to be used for a callback. + * `OnExternalCallStart` - The event handler is called whenever a user clicks a phone number in CRM object to + initiate an outbound call. + * `OnVoximplantCallEnd` - The event is raised when conversation ends (history entry). + * `OnVoximplantCallInit` - The event is raised when a call is being initialized (regarding the entry or start of + an outbound call). + * `OnVoximplantCallStart` - The event is raised when a conversation starts (operator responds to an inbound + call; call recipient responds to an outbound call). + * add `TranscriptMessage` – data structure for transcript message item + * add `TranscriptMessageSide` – enum for describe side of diarization + * add `CallType` – call types enum + * add `CrmEntityType` – crm entity type enum + * add `PbxType` – pbx type enum + * add `SipRegistrationStatus` – pbx sip line registration status +* ❗️ update scope `im`, add service `Notify`: + * `fromSystem` - Sending system notification + * `fromPersonal` - Sending personal notification + * `delete` – Deleting notification + * `markAsRead` - Cancels notification for read messages. + * `markMessagesAsRead` – "Read" the list of notifications, excluding CONFIRM notification type. + * `markMessagesAsUnread` – "Unread" the list of notifications, excluding CONFIRM notification type. + * `confirm` – Interaction with notification buttons + * `answer` – Response to notification, supporting quick reply +* change signature `Bitrix24\SDK\Core\Credentials\AccessToken::getRefreshToken()?string;` - add nullable option for + event tokens +* change signature `Bitrix24\SDK\Core\Commands\Command::getName():?string` renamed to `getId():string` +* add fields and change return types in `Bitrix24\SDK\Services\CRM\Deal\Result\DealProductRowItemResult` +* change typehints in `Bitrix24\SDK\Services\CRM\Activity\Service\Activity::add` + +### Deleted + +* remove class `Bitrix24\SDK\Application\Requests\Events\OnApplicationInstall\Auth` +* remove class `Bitrix24\SDK\Application\Requests\Events\OnApplicationUninstall\Auth` +* remove method `Bitrix24\SDK\Core\Response\Response::__destruct` +* remove interface `Bitrix24\SDK\Services\Telephony\Common\StatusSipCodeInterface` +* remove class `Bitrix24\SDK\Services\Telephony\Common\StatusSipRegistrations` +* remove class `Bitrix24\SDK\Services\Telephony\Common\TypeAtc` + +### Bugfix + +* fix [typehint for Bitrix24 User entity with field ID](https://github.com/mesilov/bitrix24-php-sdk/issues/382) +* fix [default arguments for Bitrix24 User get method](https://github.com/mesilov/bitrix24-php-sdk/issues/381) +* fix [limit argument not worked in batch list and read model](https://github.com/mesilov/bitrix24-php-sdk/issues/389) + +## 2.0-beta.2 — 1.04.2024 + +### Changed + +* updated [dependencies versions](https://github.com/mesilov/bitrix24-php-sdk/issues/373): + * require + * `psr/log` `1.4.0` → `3.0.*` + * `moneyphp/money` `4.3.*` → `4.5.*` + * require-dev + * `monolog/monolog` `2.9.*` → `3.5.*` + * `phpunit/phpunit` `10.5.*` → `11.0.*` +* added enum `DealSemanticStage` for deal field `STAGE_SEMANTIC_ID` + +## 2.0-beta.1 — 18.02.2024 + +### Added + +* ❗️add php 8.3, 8.2 support, drop 8.1 and 8.0 support +* add `Symfony\Component\Uid\Uuid` requirements +* add contracts for bitrix24 applications based on bitrix24-php-sdk - `Bitrix24\SDK\Application\Contracts`, now + added `Bitrix24Account` +* add [service builder factory](https://github.com/mesilov/bitrix24-php-sdk/issues/328) +* add method `Bitrix24\SDK\Core\Credentials\Scope::initFromString` +* add method `Bitrix24\SDK\Application\ApplicationStatus::initFromString` +* add system CRM multi-field type `Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\Phone` +* add scope `user`,`user_basic`,`user_brief`,`user.userfield` and + services [add scope user support](https://github.com/mesilov/bitrix24-php-sdk/issues/339) + * `Bitrix24\SDK\Services\User\Service\User::fields` - get user fields + * `Bitrix24\SDK\Services\User\Service\User::current` - get current user + * `Bitrix24\SDK\Services\User\Service\User::add` - add user + * `Bitrix24\SDK\Services\User\Service\User::get` - get user + * `Bitrix24\SDK\Services\User\Service\User::update` - update user + * `Bitrix24\SDK\Services\User\Service\User::search` - search users +* add method `\Bitrix24\SDK\Services\CRM\Contact\Service\Batch::update()` for batch update contacts +* add [crm item support](https://github.com/mesilov/bitrix24-php-sdk/issues/330) +* add enum `DealStageSemanticId` +* add Duplicate search support for `Bitrix24\SDK\Services\CRM\Duplicates\Service\Duplicate` +* add `x-request-id` [header support](https://github.com/mesilov/bitrix24-php-sdk/issues/354) +* add CRM multifields support [header support](https://github.com/mesilov/bitrix24-php-sdk/issues/338) + * `Email` + * `Phone` + * `Website` + * `IM` +* add [Catalog](https://github.com/mesilov/bitrix24-php-sdk/issues/364) scope services support + +### Changed + +* ❗️Batch interface `BatchInterface` [renamed](https://github.com/mesilov/bitrix24-php-sdk/issues/324) + to `Bitrix24\SDK\Core\Contracts\BatchOperationsInterface` +* ❗`Bitrix24\SDK\Services\Telephony\Requests\Events` moved to separated namespaces: + * from `Bitrix24\SDK\Services\Telephony\Requests\Events\OnVoximplantCallInit` + to `Bitrix24\SDK\Services\Telephony\Requests\Events\OnVoximplantCallInit\OnVoximplantCallInit` + * from `Bitrix24\SDK\Services\Telephony\Requests\Events\OnVoximplantCallStart` + to `Bitrix24\SDK\Services\Telephony\Requests\Events\OnVoximplantCallStart\OnVoximplantCallStart` + * from `Bitrix24\SDK\Services\Telephony\Requests\Events\OnExternalCallStart` + to `Bitrix24\SDK\Services\Telephony\Requests\Events\OnExternalCallStart\OnExternalCallStart` + * from `Bitrix24\SDK\Services\Telephony\Requests\Events\OnVoximplantCallEnd` + to `Bitrix24\SDK\Services\Telephony\Requests\Events\OnVoximplantCallEnd\OnVoximplantCallEnd` +* ❗Changes in `Bitrix24\SDK\Application\Contracts\Bitrix24Account\Bitrix24AccountInterface`: + * method `getContactPerson` renamed to `getContactPersonId` + * added method `getApplicationVersion` + * added method `updateApplicationVersion` + * added method `getApplicationScope` + * added method `applicationInstalled` + * added method `applicationUninstalled` + * added method `markAsDeactivated` + * added method `getBitrix24UserId` + * removed method `markAccountAsDeleted` + * changed method `markAsActive` +* ❗Changes in `Bitrix24\SDK\Application\Contracts\Bitrix24Account\Bitrix24AccountRepositoryInterface`: + * method `saveAccount` renamed to `save` + * method `deleteAccount` renamed to `delete` + * method `findAccountByMemberId` renamed to `findByMemberId` + * method `getAccountByMemberId` renamed to `getByMemberId` + * method `findAccountByContactPersonId` renamed to `findByContactPersonId` + * method `findAccountByDomainUrl` renamed to `findByDomainUrl` + * add method `findAllActive` + * add method `findAllDeactivated` + +### Bugfix + +* fix [typehint at ContactItemResult](https://github.com/mesilov/bitrix24-php-sdk/issues/320) +* fix [return types in DealCategoryItemResult](https://github.com/mesilov/bitrix24-php-sdk/issues/322) +* fix [add auth node in telephony voximplant events requests](https://github.com/mesilov/bitrix24-php-sdk/issues/331) +* +fix [add helper metods isError for registerCallResult fortelephony](https://github.com/mesilov/bitrix24-php-sdk/issues/335) +* fix [add return type for crm multifields phone, email, im](https://github.com/mesilov/bitrix24-php-sdk/issues/338) +* fix errors in `ShowFieldsDescriptionCommand` metadata reader CLI command +* fix errors for `ApplicationProfile` with empty scope +* fix errors in `Core` with auth attempt to non-exists portal + +### etc + +* move CLI entry point to `bin/console` + +## 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 + +* add «fast» batch-query without counting elements in result + recordset [Добавить поддержку выгрузки большого количества данных без подсчёта элементов -1](https://github.com/mesilov/bitrix24-php-sdk/issues/248) +* add `Credentials` in + CoreBuilder [set credentials from core builder](https://github.com/mesilov/bitrix24-php-sdk/pull/246) +* add method `Core\Batch::deleteEntityItems` for delete items in batch mode and integration test +* add integration test for read strategy `FilterWithBatchWithoutCountOrderTest` +* add type check in method `Core\Batch::deleteEntityItems` - only integer id allowed +* add interface `Core\Contracts\DeletedItemResultInterface` +* add in scope «CRM» `Services\CRM\Deal\Service\Batch::delete` batch delete deals +* add `symfony/stopwatch` component for integration tests +* add `/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser` for parse `curl_info` network data structures for + debug logs + in `Bitrix24\SDK\Core\Response::__destruct()` +* add `/Infrastructure/HttpClient/TransportLayer/ResponseInfoParser` for parse `bitrix24_rest_api` timing info for debug + logs + in `Bitrix24\SDK\Core\Response::__destruct()` +* add `Bitrix24\SDK\Core\BulkItemsReader` for data-intensive applications for bulk export data from Bitrix24, read + strategies located in + folder `ReadStrategies`, in services read model **must** use most effective read strategy. +* add integration tests in GitHub Actions pipeline 🎉, now integration tests run on push on `dev-branch` +* add incoming webhook for run integration tests `vendor-check.yml` from vendor CI\CD pipeline + +### Changed + +* switch `symfony/http-client` to `5.4.*` version requirement. +* switch `symfony/http-client-contracts` to `^2.5` version requirement. +* switch `symfony/event-dispatcher` to `5.4.*` version requirement. +* switch `ramsey/uuid` to `^4.2.3` version requirement. +* switch `psr/log` + to `^1.1.4 || ^2.0 || ^3.0` [version requirement](https://github.com/mesilov/bitrix24-php-sdk/issues/245). + +## 2.0-alpha.5 – 28.11.2021 + +### Added + +* add method `countByFilter` for all related services, see + issue [Добавить для всех сущностей метод подсчёта количества элементов по фильтру #228](https://github.com/mesilov/bitrix24-php-sdk/issues/228) +* add in scope «CRM» Userfield service and integration test +* add in scope «CRM» ContactUserfield service and integration test, see + issue [Добавить сервис по работе с юзерфилдами контакта #231](https://github.com/mesilov/bitrix24-php-sdk/issues/231) +* add method getUserfieldByFieldName for `ContactItemResult` +* add in scope «CRM» DealUserfield service and integration test, see + issue [Добавить сервис по работе с юзерфилдами cделки #232](https://github.com/mesilov/bitrix24-php-sdk/issues/232) +* add method getUserfieldByFieldName for `DealItemResult` +* add exception `UserfieldNotFoundException` + +### Removed + +* remove all `0.*` and `1.*` code from `2.*` branch + +### Changed + +* update type definition for `ContactItemResult`, now return types will be cast to real types: DateTimeInterface, int, + boolean etc + +## 2.0-alpha.4 – 25.11.2021 + +### Changed + +* switch `symfony/http-client` to `5.3` version requirement. +* switch `symfony/http-client-contracts` to `^2.4` version requirement. +* switch `symfony/event-dispatcher` to `5.3.*` version requirement. +* switch `ramsey/uuid` to `^4.0` version requirement. + +### Fixed + +* issue [Несовместимость с Laravel 8 #224](https://github.com/mesilov/bitrix24-php-sdk/issues/224) + +## 2.0-alpha.3 – 14.11.2021 + +* add php8 version support +* change in scope «CRM» Product service and integration tests +* add `AddedItemIdResultInterface` for batch-queries result +* add method `countByFilter` for CRM.Contact entity +* fix method name in `ContactsResult` +* add interface `ApiClientInterface` +* bump phpunit version +* bump phpstan version + +## 2.0-alpha.2 – 31.01.2021 + +* remove Travis CI and migrate to Github Actions +* add unit-tests in independent github action +* add phpstan checks in independent github action +* add in scope «CRM» Contacts service and integration test +* add in scope «CRM» Contacts batch service and integration test +* add in scope «CRM» Products service and integration test +* add in scope «CRM» Settings service and integration test +* add in scope «CRM» DealCategoryStage service and integration test +* add in scope «CRM» DealProductRows service and integration test +* add in scope «CRM» DealContact service and integration test +* add in scope «IM» IM service and integration test +* add in default scope «Main» default service + +## 2.0-alpha.1 – 11.07.2020 + +* remove all v1 code +* migrate to Symfony HttpClient +* add documentation webhook auth type +* add OAuth 2.0 support +* add Events support + +## 0.1.0 (14.11.2021) + +branch version 1.x – bugfix and security releases only + +## 0.7.0 (11.07.2020) + +* add arguments in method `Bitrix24\Bizproc\Robot::add` for return results support + +## 0.6.2 (12.09.2019) + +* remove in method, `processBatchCalls` remove call `handleBitrix24APILevelErrors` +* remove php 5.x branch in travis config + +## 0.6.1 (20.03.2019) + +* add `offset` parameter to entity `CRM\Status\Status` in method `getList` +* add `offset` parameter to entity `User\User` in method `getList` +* add method `messageAdd` to entity `Bitrix24\Bitrix24` +* add method `setEnabledSslVerify` to entity `Classes\Im\Im` +* add entity `Bitrix24\Bizproc\Provider` +* add entity `Bitrix24\CRM\Lead\ProductRows` class to work with products +* fix error in method `crm.company.update` +* fix error in method `Bitrix24::getNewAccessToken` +* fix error in method `Bizproc\Robot::add` +* fix log level in method `Bitrix24::handleBitrix24APILevelErrors` + +## 0.6.0 (18.02.2018) + +* add support for `FaceTracker` entity +* add presets for request timing information +* add all methods for sonetgroup +* add method `crm.contact.userfield.update` +* add activities methods +* add exception `Bitrix24PortalRenamedException` +* add a pair of fields for the Lead +* add requisite support +* add method update to deal\userfield entity +* add `Product\Property` support +* add method `crm.product.delete` +* add method `crm.product.fields` +* add method `crm.product.property.types` +* add method `crm.product.property.delete` +* add methods for `\Bitrix24\CRM\Status` +* add new placement presets for detail page + ## 0.5.4 (8.07.2017) + * add Callback for expired token. Fix pullrequest#63 by valga * add method `update` in class `Bitrix24\CRM\Product` * increased curl time out @@ -7,32 +513,45 @@ * add batch calls method to bitrix24 api client interface ## 0.5.3 (20.05.2017) + * add class `Bitrix24\Placement\Placement` * add preset `Bitrix24\Presets\Placement\Placement` with placement codes * add preset `Bitrix24\Presets\Placement\Fields` with placement fields ## 0.5.2 (11.05.2017) + * add preset `Bitrix24\Presets\CRM\Product\ProductRowFields` * updated preset `Bitrix24\Presets\CRM\Contact\Fields` * updated preset `Bitrix24\Presets\CRM\Deal\Fields` * updated preset `Bitrix24\Presets\CRM\Lead\Fields` ## 0.5.1 (30.04.2017) + * add preset `Bitrix24\Presets\CRM\Product\Fields` * add method `add` in class `Bitrix24\CRM\Product` ## 0.5.0 (4.09.2016) -* add class `Bitrix24\CRM\Quote` see pr [Added support for Quote API calls](https://github.com/mesilov/bitrix24-php-sdk/pull/53/) -* add support http status 301 moved permanently in class `Bitrix24` see issue [301 Moved Permanently #49](https://github.com/mesilov/bitrix24-php-sdk/issues/49) -* fixed bug in class `Bitrix24` see pr [Issue in the isAccessTokenExpire method](https://github.com/mesilov/bitrix24-php-sdk/pull/54) + +* add class `Bitrix24\CRM\Quote` see + pr [Added support for Quote API calls](https://github.com/mesilov/bitrix24-php-sdk/pull/53/) +* add support http status 301 moved permanently in class `Bitrix24` see + issue [301 Moved Permanently #49](https://github.com/mesilov/bitrix24-php-sdk/issues/49) +* fixed bug in class `Bitrix24` see + pr [Issue in the isAccessTokenExpire method](https://github.com/mesilov/bitrix24-php-sdk/pull/54) ## 0.4.1 (4.08.2016) -* add new events in class `Bitrix24\Presets\Event\Event` see issue [Add new bitrix24 events #44](https://github.com/mesilov/bitrix24-php-sdk/issues/44) -* add new scope in class `Bitrix24\Presets\Scope` see issue [Update scope presets class #47](https://github.com/mesilov/bitrix24-php-sdk/issues/47) -* remove file with old deprecated exceptions see issue [Move all exceptions in namespace «Exceptions» #46](https://github.com/mesilov/bitrix24-php-sdk/issues/46) + +* add new events in class `Bitrix24\Presets\Event\Event` see + issue [Add new bitrix24 events #44](https://github.com/mesilov/bitrix24-php-sdk/issues/44) +* add new scope in class `Bitrix24\Presets\Scope` see + issue [Update scope presets class #47](https://github.com/mesilov/bitrix24-php-sdk/issues/47) +* remove file with old deprecated exceptions see + issue [Move all exceptions in namespace «Exceptions» #46](https://github.com/mesilov/bitrix24-php-sdk/issues/46) ## 0.4.0 (16.07.2016) -* remove all exceptions in namespace `\Exceptions` see issue [Move all exceptions in namespace «Exceptions» #46](https://github.com/mesilov/bitrix24-php-sdk/issues/46) + +* remove all exceptions in namespace `\Exceptions` see + issue [Move all exceptions in namespace «Exceptions» #46](https://github.com/mesilov/bitrix24-php-sdk/issues/46) * add class `Bitrix24\Exceptions\Bitrix24Exception` * add class `Bitrix24\Exceptions\Bitrix24IoException` * add class `Bitrix24\Exceptions\Bitrix24EmptyResponseException` @@ -56,37 +575,48 @@ * updated class `Bitrix24\Bitrix24SecurityException` mark as **deprecated** ## 0.3.4 (06.06.2016) + * add exception class `Bitrix24EmptyResponseException` * in class `Bitrix24` add debug information for some error types -* temporary remove calls to oauth.bitrix.info for methods `app.info` and `app.stat` see issue [Fix errors after change REST API to support self hosted version #43](https://github.com/mesilov/bitrix24-php-sdk/issues/43) +* temporary remove calls to oauth.bitrix.info for methods `app.info` and `app.stat` see + issue [Fix errors after change REST API to support self hosted version #43](https://github.com/mesilov/bitrix24-php-sdk/issues/43) ## 0.3.3 (28.05.2016) -* fixed bug in class `Bitrix24` see issue [Fix errors after change REST API to support self hosted version #43](https://github.com/mesilov/bitrix24-php-sdk/issues/43) + +* fixed bug in class `Bitrix24` see + issue [Fix errors after change REST API to support self hosted version #43](https://github.com/mesilov/bitrix24-php-sdk/issues/43) ## 0.3.2 (07.05.2016) -* fixed bug in class `Bitrix24\Im\Notify` see issue [ATTACH_ERROR for calls method im.notify for empty attach #42](https://github.com/mesilov/bitrix24-php-sdk/issues/42) - + +* fixed bug in class `Bitrix24\Im\Notify` see + issue [ATTACH_ERROR for calls method im.notify for empty attach #42](https://github.com/mesilov/bitrix24-php-sdk/issues/42) + ## 0.3.1 (04.05.2016) + * add `dev` branch in GitHub repo * fixed bug in class `Bitrix24\Im\Attach\Attach`, method `Attach::getAttachItems()` already return array ## 0.3.0 (04.05.2016) + * add class `Bitrix24\Im\Attach\Item\Message` class implements work with string messages in attach item -* add interface `Bitrix24\Presets\Im\iChatColor` with chat color presets +* add interface `Bitrix24\Presets\Im\iChatColor` with chat color presets * add phpUnit tests for items: - * `Bitrix24\Im\Attach\Item\Delimiter` - * `Bitrix24\Im\Attach\Item\File` - * `Bitrix24\Im\Attach\Item\Grid` - * `Bitrix24\Im\Attach\Item\Image` - * `Bitrix24\Im\Attach\Item\Link` - * `Bitrix24\Im\Attach\Item\Message` - * `Bitrix24\Im\Attach\Item\User` -* fixed bug in class `Bitrix24\Im\Attach\Attach` + * `Bitrix24\Im\Attach\Item\Delimiter` + * `Bitrix24\Im\Attach\Item\File` + * `Bitrix24\Im\Attach\Item\Grid` + * `Bitrix24\Im\Attach\Item\Image` + * `Bitrix24\Im\Attach\Item\Link` + * `Bitrix24\Im\Attach\Item\Message` + * `Bitrix24\Im\Attach\Item\User` +* fixed bug in class `Bitrix24\Im\Attach\Attach` ## 0.2.1 (27.04.2016) -* add exception class `Bitrix24PortalDeleted` and handle Bitrix24 portal deleted event. See issue [Add support for deleted portals #40](https://github.com/mesilov/bitrix24-php-sdk/issues/40) + +* add exception class `Bitrix24PortalDeleted` and handle Bitrix24 portal deleted event. See + issue [Add support for deleted portals #40](https://github.com/mesilov/bitrix24-php-sdk/issues/40) ## 0.2.0 (24.06.2015) + * add class `Deal` * add class `LiveFeedMessage` * add task fields presets @@ -105,6 +635,7 @@ * remove class `Bitrix24\Task\TaskItem` ## 0.1.4 (18.04.2015) + * add presets for user fields data type structure * add method `Update` and predefined constants in class `Invoice` * add protected method `handleBitrix24APILevelErrors` in a base class @@ -119,6 +650,7 @@ * fixed bug in Fix method isAccessTokenExpire ## 0.1.3 (24.08.2014) + * add const `TOTAL` and `RESULT` for class `Bitrix24\Presets\Main` * add class `Bitrix24\Presets\Users\Fields` for Bitrix24 users fields * add class `Bitrix24\Departments\Department` @@ -134,6 +666,7 @@ * fixed bug in __construct in abstract class `Bitrix24Entity` ## 0.1.2 (22.01.2014) + * add security sign support in api-call * add class `User` * add method «admin» — Check is current user admin @@ -142,9 +675,11 @@ * add MIT-LICENSE ## 0.1.1 (9.10.2013) + * add namespace support * add classes of Bitrix24 parts: tasks, sonet * add base class `Bitrix24Entity` ## 0.1.0 (26.10.2013) + * Initial release \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..2a796ee0 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,38 @@ +# 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. + +## 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 execute: + +```shell +make lint-phpstan +make lint-rector +make lint-rector-fix +``` + +## 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..ab879502 100644 --- a/MIT-LICENSE.txt +++ b/MIT-LICENSE.txt @@ -1,5 +1,4 @@ -Copyright 2013 Mesilov Maxim -https://bitrixinsider.ru/ +Copyright 2024 Maksim 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/Makefile b/Makefile new file mode 100644 index 00000000..963281b6 --- /dev/null +++ b/Makefile @@ -0,0 +1,54 @@ +# This file is part of the bitrix24-php-sdk package. +# +# © Maksim Mesilov +# +# For the full copyright and license information, please view the MIT-LICENSE.txt +# file that was distributed with this source code. + +default: + @echo "make needs target:" + @egrep -e '^\S+' ./Makefile | grep -v default | sed -r 's/://' | sed -r 's/^/ - /' + +# load default and personal env-variables +ENV := $(PWD)/tests/.env +ENV_LOCAL := $(PWD)/tests/.env.local +include $(ENV) +include $(ENV_LOCAL) + +debug-show-env: + @echo BITRIX24_WEBHOOK $(BITRIX24_WEBHOOK) + @echo DOCUMENTATION_DEFAULT_TARGET_BRANCH $(DOCUMENTATION_DEFAULT_TARGET_BRANCH) + +# build documentation +build-documentation: + php bin/console b24:util:generate-coverage-documentation --webhook=$(BITRIX24_WEBHOOK) --repository-url=https://github.com/mesilov/bitrix24-php-sdk --repository-branch=$(DOCUMENTATION_DEFAULT_TARGET_BRANCH) --file=docs/EN/Services/bitrix24-php-sdk-methods.md + +# linters +lint-phpstan: + vendor/bin/phpstan --memory-limit=1G analyse +lint-rector: + vendor/bin/rector process --dry-run +lint-rector-fix: + vendor/bin/rector process + +# unit tests +test-unit: + vendor/bin/phpunit --testsuite unit_tests --display-warnings + +# integration tests with granularity by api-scope +test-integration-scope-telephony: + vendor/bin/phpunit --testsuite integration_tests_scope_telephony +test-integration-scope-workflows: + vendor/bin/phpunit --testsuite integration_tests_scope_workflows +test-integration-scope-im: + vendor/bin/phpunit --testsuite integration_tests_scope_im +test-integration-scope-placement: + vendor/bin/phpunit --testsuite integration_tests_scope_placement +test-integration-scope-im-open-lines: + vendor/bin/phpunit --testsuite integration_tests_scope_im_open_lines +test-integration-scope-user: + vendor/bin/phpunit --testsuite integration_tests_scope_user +test-integration-scope-user-consent: + vendor/bin/phpunit --testsuite integration_tests_scope_user_consent +test-integration-core: + vendor/bin/phpunit --testsuite integration_tests_core \ No newline at end of file diff --git a/README.md b/README.md index bb2bbc92..f184775b 100644 --- a/README.md +++ b/README.md @@ -1,52 +1,337 @@ -bitrix24-php-sdk [![Build Status](https://travis-ci.org/mesilov/bitrix24-php-sdk.svg?branch=master)](https://travis-ci.org/mesilov/bitrix24-php-sdk) +❗️Bitrix24 forked this repository 🥳 and now I contribute [there](https://github.com/bitrix24/b24phpsdk) +================ + +❗️For new and existing projects please use https://github.com/bitrix24/b24phpsdk +================ + +Bitrix24 REST API PHP SDK ================ [![License](https://poser.pugx.org/mesilov/bitrix24-php-sdk/license.svg)](https://packagist.org/packages/mesilov/bitrix24-php-sdk) [![Total Downloads](https://poser.pugx.org/mesilov/bitrix24-php-sdk/downloads.svg)](https://packagist.org/packages/mesilov/bitrix24-php-sdk) +[![Latest Stable Version](https://img.shields.io/packagist/v/mesilov/bitrix24-php-sdk.svg)](https://packagist.org/packages/mesilov/bitrix24-php-sdk) + +A powerful PHP library for the Bitrix24 REST API + +## Build status + +| CI\CD [status](https://github.com/mesilov/bitrix24-php-sdk/actions) on `master` | +|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| [![phpstan check](https://github.com/mesilov/bitrix24-php-sdk/actions/workflows/phpstan.yml/badge.svg)](https://github.com/mesilov/bitrix24-php-sdk/actions/workflows/phpstan.yml) | +| [![unit-tests status](https://github.com/mesilov/bitrix24-php-sdk/actions/workflows/phpunit.yml/badge.svg)](https://github.com/mesilov/bitrix24-php-sdk/actions/workflows/phpunit.yml) | + +Integration tests run in GitHub actions with real Bitrix24 portal + +## BITRIX24-PHP-SDK ✨FEATURES✨ + +Support both auth modes: + +- [x] work with auth tokens for Bitrix24 applications in marketplace +- [x] work with incoming webhooks for simple integration projects for current portal + +Domain core events: + +- [x] Access Token expired +- [x] Bitrix24 portal domain url changed -A powerfull PHP library for the Bitrix24 REST API +API - level features -[Bitrix24 API documentation - Russian](http://dev.1c-bitrix.ru/rest_help/)
-[Bitrix24 API documentation - English](https://training.bitrix24.com/rest_help/) -## Promo code for new Bitrix24 accounts -- `b24io5gb` — add 5GB on your Bitrix24 -- `b24iousers` — add 12 users on your Bitrix24 +- [x] Auto renew access tokens +- [x] List queries with «start=-1» support +- [ ] offline queues -[Register new Bitrix24 account](https://www.bitrix24.ru/create.php?p=255670) +Performance improvements 🚀 + +- [x] Batch queries implemented with [PHP Generators](https://www.php.net/manual/en/language.generators.overview.php) – + constant low memory and low CPI usage: +- [x] batch read data from bitrix24 +- [x] batch write data to bitrix24 +- [x] read without count flag + +## Development principles + +- Good developer experience + - auto-completion of methods at the IDE + - typed method call signatures + - typed results of method calls + - helpers for typical operations +- Good documentation + - documentation on the operation of a specific method containing a link to the official documentation + - documentation for working with the SDK +- Performance first: + - minimal impact on client code + - ability to work with large amounts of data with constant memory consumption + - efficient operation of the API using batch requests +- Modern technology stack + - based on [Symfony HttpClient](https://symfony.com/doc/current/http_client.html) + - actual PHP versions language features +- Reliable: + - test coverage: unit, integration, contract + - typical examples typical for different modes of operation and they are optimized for memory \ performance + +## Architecture + +### Abstraction layers + +``` +- http2 protocol via json data structures +- symfony http client +- \Bitrix24\SDK\Core\ApiClient - work with b24 rest-api endpoints + input: arrays \ strings + output: Symfony\Contracts\HttpClient\ResponseInterface, operate with strings + process: network operations +- \Bitrix24\SDK\Services\* - work with b24 rest-api entities + input: arrays \ strings + output: b24 response dto + process: b24 entities, operate with immutable objects +``` + +## Documentation + +- [Bitrix24 API documentation - English](https://training.bitrix24.com/rest_help/) +- [Internal documentation](docs/EN/documentation.md) for bitrix24-php-sdk ## Requirements -- php: >=5.3.2 + +- php: >=8.2 - ext-json: * - ext-curl: * -- Monolog: optional -## Example ## -``` php - + see example.php file + +```php +declare(strict_types=1); + +use Bitrix24\SDK\Services\ServiceBuilderFactory; +use Symfony\Component\EventDispatcher\EventDispatcher; use Monolog\Logger; use Monolog\Handler\StreamHandler; +use Monolog\Processor\MemoryUsageProcessor; + +require_once 'vendor/autoload.php'; + +$webhookUrl = 'INSERT_HERE_YOUR_WEBHOOK_URL'; + +$log = new Logger('bitrix24-php-sdk'); +$log->pushHandler(new StreamHandler('bitrix24-php-sdk.log')); +$log->pushProcessor(new MemoryUsageProcessor(true, true)); + +// create service builder factory +$b24ServiceFactory = new ServiceBuilderFactory(new EventDispatcher(), $log); +// init bitrix24-php-sdk service from webhook +$b24Service = $b24ServiceFactory->initFromWebhook($webhookUrl); + +// work with interested scope +var_dump($b24Service->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()); +// get deals list and address to first element +var_dump($b24Service->getCRMScope()->lead()->list([], [], ['ID', 'TITLE'])->getLeads()[0]->TITLE); +``` + + + +5. Call php file in shell + +```shell +php -f example.php +``` + +### Work with local application + +1. Go to `/examples/local-application` folder +2. Open console and install dependencies + +```shell +composer install +``` + +3. Start local development server + +```shell +sudo php -S 127.0.0.1:80 +``` + +4. Expose local server to public via [ngrok](https://ngrok.com/) and remember temporally public url – + `https://****.ngrok-free.app` + +```shell +ngrok http 127.0.0.1 +``` + +5. Check public url from ngrok and see `x-powered-by` header with **200** status-code. + +```shell +curl https://****.ngrok-free.app -I +HTTP/2 200 +content-type: text/html; charset=UTF-8 +date: Mon, 26 Aug 2024 19:09:24 GMT +host: ****.ngrok-free.app +x-powered-by: PHP/8.3.8 +``` + +6. Open Bitrix24 portal: Developer resources → Other → Local application and create new local application: + - `type`: server + - `handler path`: `https://****.ngrok-free.app/index.php` + - `Initial installation path`: `https://****.ngrok-free.app/install.php` + - `Menu item text`: `Test local app` + - `scope`: `crm` +7. Save application parameters in `index.php` file: + - `Application ID (client_id)` — `BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID` + - `Application key (client_secret)` — `BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET` + - `Assing permitions (scope)` — `BITRIX24_PHP_SDK_APPLICATION_SCOPE` +
+ see index.php file + +```php +declare(strict_types=1); + +use Bitrix24\SDK\Core\Credentials\AuthToken; +use Bitrix24\SDK\Core\Credentials\ApplicationProfile; +use Bitrix24\SDK\Services\ServiceBuilderFactory; +use Monolog\Handler\StreamHandler; +use Monolog\Logger; +use Monolog\Processor\MemoryUsageProcessor; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\HttpFoundation\Request; + +require_once 'vendor/autoload.php'; +?> +
+    Application is worked, auth tokens from bitrix24:
+    
+
+pushHandler(new StreamHandler('bitrix24-php-sdk.log')); +$log->pushProcessor(new MemoryUsageProcessor(true, true)); + +$b24ServiceBuilderFactory = new ServiceBuilderFactory(new EventDispatcher(), $log); +$appProfile = ApplicationProfile::initFromArray([ + 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID' => 'INSERT_HERE_YOUR_DATA', + 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET' => 'INSERT_HERE_YOUR_DATA', + 'BITRIX24_PHP_SDK_APPLICATION_SCOPE' => 'INSERT_HERE_YOUR_DATA' +]); +$b24Service = $b24ServiceBuilderFactory->initFromRequest($appProfile, AuthToken::initFromPlacementRequest($request), $request->get('DOMAIN')); + +var_dump($b24Service->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()); +// get deals list and address to first element +var_dump($b24Service->getCRMScope()->lead()->list([], [], ['ID', 'TITLE'])->getLeads()[0]->TITLE); +``` + +
+8. Save local application in Bitrix24 tab and press «OPEN APPLICATION» button. + + +### Create application for Bitrix24 marketplace + +if you want to create application you can use production-ready contracts in namespace +`Bitrix24\SDK\Application\Contracts`: + +- `Bitrix24Accounts` — Store auth tokens and + provides [methods](src/Application/Contracts/Bitrix24Accounts/Docs/Bitrix24Accounts.md) for work with Bitrix24 + account. +- `ApplicationInstallations` — Store information + about [application installation](src/Application/Contracts/ApplicationInstallations/Docs/ApplicationInstallations.md), + linked with Bitrix24 Account with auth + tokens. Optional can store links to: + - Client contact person: client person who responsible for application usage + - Bitrix24 Partner contact person: partner contact person who supports client and configure application + - Bitrix24 Partner: partner who supports client portal +- `ContactPersons` – Store information [about person](src/Application/Contracts/ContactPersons/Docs/ContactPersons.md) + who installed application. +- `Bitrix24Partners` – Store information + about [Bitrix24 Partner](src/Application/Contracts/Bitrix24Partners/Docs/Bitrix24Partners.md) who supports client + portal and install or configure application. + +Steps: + +1. Create own entity of this bounded contexts. +2. Implement all methods in contract interfaces. +3. Test own implementation behavior with contract-tests `tests/Unit/Application/Contracts/*` – examples. + +## Tests -// create a log channel -$log = new Logger('bitrix24'); -$log->pushHandler(new StreamHandler('path/to/your.log', Logger::DEBUG)); +Tests locate in folder `tests` and we have two test types. +In folder tests create file `.env.local` and fill environment variables from `.env`. +### PHP Static Analysis Tool – phpstan -// init lib -$obB24App = new \Bitrix24\Bitrix24(false, $log); -$obB24App->setApplicationScope($arParams['B24_APPLICATION_SCOPE']); -$obB24App->setApplicationId($arParams['B24_APPLICATION_ID']); -$obB24App->setApplicationSecret($arParams['B24_APPLICATION_SECRET']); - -// set user-specific settings -$obB24App->setDomain($arParams['DOMAIN']); -$obB24App->setMemberId($arParams['MEMBER_ID']); -$obB24App->setAccessToken($arParams['AUTH_ID']); -$obB24App->setRefreshToken($arParams['REFRESH_ID']); +Call in command line -// get information about current user from bitrix24 -$obB24User = new \Bitrix24\User\User($obB24App); -$arCurrentB24User = $obB24User->current(); +```shell +make lint-phpstan +``` + +### PHP Static Analysis Tool – rector + +Call in command line for validate + +```shell +make lint-rector +``` + +Call in command line for fix codebase + +```shell +make lint-rector-fix +``` + +### Unit tests + +**Fast**, in-memory tests without a network I\O For run unit tests you must call in command line + +```shell +make test-unit +``` + +### Integration tests + +**Slow** tests with full lifecycle with your **test** Bitrix24 portal via webhook. + +❗️Do not run integration tests with production portals + +For run integration test you must: + +1. Create new Bitrix24 portal for development tests. +2. Go to left menu, click «Sitemap». +3. Find menu item «Developer resources». +4. Click on menu item «Other». +5. Click on menu item «Inbound webhook». +6. Assign all permisions with webhook and click «save» button. +7. Create file `/tests/.env.local` with same settings, see comments in `/tests/.env` file. + +```yaml +APP_ENV=dev +BITRIX24_WEBHOOK=https:// your portal webhook url +INTEGRATION_TEST_LOG_LEVEL=500 +``` + +8. call in command line + +```shell +make test-integration-core +make test-integration-scope-telephony +make test-integration-scope-workflows +make test-integration-scope-user ``` -## Installation ## -Add `"mesilov/bitrix24-php-sdk": "dev-master"` to `composer.json` of your application. Or clone repo to your project. ## Submitting bugs and feature requests @@ -56,10 +341,17 @@ Bugs and feature request are tracked on [GitHub](https://github.com/mesilov/bitr bitrix24-php-sdk is licensed under the MIT License - see the `MIT-LICENSE.txt` file for details -## Author +## Authors + +Maksim Mesilov - mesilov.maxim@gmail.com + +See also the list of [contributors](https://github.com/mesilov/bitrix24-php-sdk/graphs/contributors) which participated +in this project. + +## Sponsors + +[boosty.to/bitrix24-php-sdk](https://boosty.to/bitrix24-php-sdk) -Maxim Mesilov - -
-See also the list of [contributors](https://github.com/mesilov/bitrix24-php-sdk/graphs/contributors) which participated in this project. +## Need custom Bitrix24 application? -## Need custom Bitrix24 application? ## -email: +Email to mesilov.maxim@gmail.com for private consultations or dedicated support. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..96736b8c --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,12 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +| ------- | ------------------ | +| 2.x | :white_check_mark: | +| 1.x | :x: | +| 0.x | :x: | + +## Reporting a Vulnerability +Create issue with vulnerability details \ No newline at end of file diff --git a/bin/console b/bin/console new file mode 100644 index 00000000..b94007cc --- /dev/null +++ b/bin/console @@ -0,0 +1,78 @@ +#!/usr/bin/env php + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +use Bitrix24\SDK\Attributes\Services\AttributesParser; +use Bitrix24\SDK\Services\ServiceBuilderFactory; +use Bitrix24\SDK\Tools\Commands\CopyPropertyValues; +use Bitrix24\SDK\Tools\Commands\GenerateContactsCommand; +use Bitrix24\SDK\Infrastructure\Console\Commands; +use Bitrix24\SDK\Tools\Commands\PerformanceBenchmarks\ListCommand; +use Bitrix24\SDK\Tools\Commands\ShowFieldsDescriptionCommand; +use Monolog\Handler\StreamHandler; +use Monolog\Logger; +use Monolog\Processor\MemoryUsageProcessor; +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Input\ArgvInput; +use Symfony\Component\Dotenv\Dotenv; +use Symfony\Component\ErrorHandler\Debug; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Typhoon\Reflection\TyphoonReflector; + +if (!in_array(PHP_SAPI, ['cli', 'phpdbg', 'embed'], true)) { + echo 'Warning: The console should be invoked via the CLI version of PHP, not the ' . PHP_SAPI . ' SAPI' . PHP_EOL; +} + +set_time_limit(0); + +require dirname(__DIR__) . '/vendor/autoload.php'; + +if (!class_exists(Dotenv::class)) { + throw new LogicException('You need to add "symfony/dotenv" as Composer dependencies.'); +} + +$input = new ArgvInput(); +if (null !== $env = $input->getParameterOption(['--env', '-e'], null, true)) { + putenv('APP_ENV=' . $_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = $env); +} + +if ($input->hasParameterOption('--no-debug', true)) { + putenv('APP_DEBUG=' . $_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = '0'); +} + +(new Dotenv())->bootEnv(dirname(__DIR__) . '/tools/.env'); + +if ($_SERVER['APP_DEBUG']) { + umask(0000); + + if (class_exists( + Debug::class + )) { + Debug::enable(); + } +} + +$log = new Logger('bitrix24-php-sdk-cli'); +$log->pushHandler(new StreamHandler($_ENV['LOGS_FILE'], (int)$_ENV['LOGS_LEVEL'])); +$log->pushProcessor(new MemoryUsageProcessor(true, true)); + +$application = new Application(); +$application->add(new GenerateContactsCommand($log)); +$application->add(new ListCommand($log)); +$application->add(new ShowFieldsDescriptionCommand($log)); +$application->add(new CopyPropertyValues($log)); +$application->add(new Commands\GenerateCoverageDocumentationCommand( + new AttributesParser(TyphoonReflector::build(), new Symfony\Component\Filesystem\Filesystem()), + new ServiceBuilderFactory(new EventDispatcher(), $log), + new Symfony\Component\Finder\Finder(), + new Symfony\Component\Filesystem\Filesystem(), + $log)); +$application->run($input); \ No newline at end of file diff --git a/composer.json b/composer.json index dcd28c60..36f3e0d1 100644 --- a/composer.json +++ b/composer.json @@ -1,35 +1,83 @@ { - "name": "mesilov/bitrix24-php-sdk", - "description": "A powerfull PHP library for the Bitrix24 REST API", - "keywords": ["Bitrix24", "PHP", "REST", "API"], - "type": "library", - "homepage": "https://github.com/mesilov/bitrix24-php-sdk", - "license": "MIT", - "authors": [ - { - "name": "Maxim Mesilov", - "homepage": "https://github.com/mesilov/" - } - ], - "require": { - "php": ">=5.3.2", - "ext-json": "*", - "ext-curl": "*", - "psr/log": "^1.0" - }, - "require-dev": { - "jakub-onderka/php-parallel-lint": "0.9", - "jakub-onderka/php-console-highlighter": "~0.3", - "phpunit/phpunit": "~4.8", - "phpunit/phpunit-mock-objects": "2.3.0" - }, - "autoload": { - "classmap": ["src/"] - }, - "scripts": { - "test": [ - "parallel-lint . --exclude vendor --no-colors", - "phpunit --colors=always --verbose" - ] + "name": "mesilov/bitrix24-php-sdk", + "description": "A powerful PHP library for the Bitrix24 REST API", + "keywords": [ + "Bitrix24", + "PHP", + "REST", + "API" + ], + "type": "library", + "homepage": "https://github.com/mesilov/bitrix24-php-sdk", + "license": "MIT", + "authors": [ + { + "name": "Maksim Mesilov", + "homepage": "https://github.com/mesilov/" + } + ], + "config": { + "sort-packages": true, + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } + }, + "require": { + "php": "8.2.* || 8.3.*", + "ext-json": "*", + "ext-curl": "*", + "ext-intl": "*", + "psr/log": "^2 || ^3", + "fig/http-message-util": "^1", + "giggsey/libphonenumber-for-php": "^8", + "darsyn/ip": "^4 || ^5", + "nesbot/carbon": "^3", + "moneyphp/money": "^3 || ^4", + "mesilov/moneyphp-percentage": "^0.2", + "symfony/http-client": "^6 || ^7", + "symfony/console": "^6 || ^7", + "symfony/dotenv": "^6 || ^7", + "symfony/filesystem": "^6 || ^7", + "symfony/mime": "^6 || ^7", + "symfony/finder": "^6 || ^7", + "symfony/http-client-contracts": "^2 || ^3", + "symfony/http-foundation": "^6 || ^7", + "symfony/event-dispatcher": "^6 || ^7", + "symfony/uid": "^6 || ^7" + }, + "require-dev": { + "fakerphp/faker": "^1", + "monolog/monolog": "^3", + "nunomaduro/phpinsights": "^2", + "phpstan/phpstan": "1.11.7", + "phpunit/phpunit": "^10 || ^11", + "psalm/phar": "^5", + "rector/rector": "^1", + "roave/security-advisories": "dev-master", + "symfony/debug-bundle": "^6 || ^7", + "symfony/stopwatch": "^6 || ^7", + "typhoon/reflection": "^0.4" + }, + "autoload": { + "psr-4": { + "Bitrix24\\SDK\\": "src" } -} \ No newline at end of file + }, + "autoload-dev": { + "psr-4": { + "Bitrix24\\SDK\\Tools\\": "tools", + "Bitrix24\\SDK\\Tests\\": "tests" + } + }, + "scripts": { + "phpunit-run-unit-tests": [ + "phpunit --testsuite unit_tests" + ], + "phpunit-run-integration-tests": [ + "phpunit --testsuite integration_tests" + ], + "phpstan-analyse": [ + "vendor/bin/phpstan analyse --memory-limit 1G" + ] + } +} diff --git a/docs/EN/Core/Auth/auth.md b/docs/EN/Core/Auth/auth.md new file mode 100644 index 00000000..f4994018 --- /dev/null +++ b/docs/EN/Core/Auth/auth.md @@ -0,0 +1,38 @@ +Auth with incoming WebHook + +## Documentation +[WebHooks](https://training.bitrix24.com/rest_help/rest_sum/webhooks.php) + +## use web-hooks +1. Create WebHook +2. install bitrix24-php-sdk +3. Configure ApiClient for webhook auth + +```php +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('https://test.bitrix24.ru/rest/7/9kc3tt3kr7qxjt0c/'), + null, + null +); + +$apiClient = new \Bitrix24\SDK\Core\ApiClient($credentials, $client, $log); + +$result = $apiClient->getResponse('app.info'); +$result = json_decode($result->getContent(), true); +var_dump($result); +``` + diff --git a/docs/EN/Development/dev.md b/docs/EN/Development/dev.md new file mode 100644 index 00000000..2e35896c --- /dev/null +++ b/docs/EN/Development/dev.md @@ -0,0 +1,17 @@ +# How to build bitrix24-php-sdk + +## How to rebuild documentation + +Use cli-command + +```shell +make build-documentation +``` + +## How to add new scope + +1. Add new scope in scope enum `src/Core/Credentials/Scope.php`. +2. Add new scope folder in `src/Services/` folder and add services. +3. Add new integration tests in mirror scope folder in `tests/Integration/Services`. +4. Add new scope support in phpunit `phpunit.xml.dist` testsuite list +5. Add new scope support in `Makefile` \ No newline at end of file diff --git a/docs/EN/Services/bitrix24-php-sdk-methods.md b/docs/EN/Services/bitrix24-php-sdk-methods.md new file mode 100644 index 00000000..4f91a451 --- /dev/null +++ b/docs/EN/Services/bitrix24-php-sdk-methods.md @@ -0,0 +1,164 @@ +## All bitrix24-php-sdk methods + +| **Scope** | **API method with documentation** | **Description** | Method in SDK | +|-----------|----------------------------------------|------------------|----------------| +|`–`|[server.time](https://training.bitrix24.com/rest_help/general/server_time.php)|Method returns current server time in the format YYYY-MM-DDThh:mm:ss±hh:mm.|[`Bitrix24\SDK\Services\Main\Service\Main::getServerTime`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Main/Service/Main.php#L44-L47)
Return type
[`Bitrix24\SDK\Services\Main\Result\ServerTimeResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Main/Result/ServerTimeResult.php)| +|`–`|[profile](https://training.bitrix24.com/rest_help/general/profile.php)|Allows to return basic Information about the current user without any scopes, in contrast to user.current.|[`Bitrix24\SDK\Services\Main\Service\Main::getCurrentUserProfile`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Main/Service/Main.php#L61-L64)
Return type
[`Bitrix24\SDK\Services\Main\Result\UserProfileResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Main/Result/UserProfileResult.php)| +|`–`|[access.name](https://training.bitrix24.com/rest_help/general/access_name.php)|Returns access permission names.|[`Bitrix24\SDK\Services\Main\Service\Main::getAccessName`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Main/Service/Main.php#L79-L84)
Return type
[`Bitrix24\SDK\Core\Response\Response`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Response/Response.php)| +|`–`|[user.access](https://training.bitrix24.com/rest_help/general/user_access.php)|Checks if the current user has at least one permission of those specified by the ACCESS parameter.|[`Bitrix24\SDK\Services\Main\Service\Main::checkUserAccess`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Main/Service/Main.php#L99-L104)
Return type
[`Bitrix24\SDK\Core\Response\Response`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Response/Response.php)| +|`–`|[method.get](https://training.bitrix24.com/rest_help/general/method_get.php)|Method returns 2 parameters - isExisting and isAvailable|[`Bitrix24\SDK\Services\Main\Service\Main::getMethodAffordability`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Main/Service/Main.php#L119-L126)
Return type
[`Bitrix24\SDK\Services\Main\Result\MethodAffordabilityResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Main/Result/MethodAffordabilityResult.php)| +|`–`|[scope](https://training.bitrix24.com/rest_help/general/scope.php)|Method will return a list of all possible permissions.|[`Bitrix24\SDK\Services\Main\Service\Main::getAvailableScope`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Main/Service/Main.php#L157-L160)
Return type
[`Bitrix24\SDK\Core\Response\Response`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Response/Response.php)| +|`–`|[methods](https://training.bitrix24.com/rest_help/general/methods.php)|Returns the methods available to the current application|[`Bitrix24\SDK\Services\Main\Service\Main::getMethodsByScope`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Main/Service/Main.php#L212-L215)
Return type
[`Bitrix24\SDK\Core\Response\Response`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Response/Response.php)| +|`–`|[app.info](https://training.bitrix24.com/rest_help/general/app_info.php)|Displays application information. The method supports secure calling convention.|[`Bitrix24\SDK\Services\Main\Service\Main::getApplicationInfo`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Main/Service/Main.php#L229-L232)
Return type
[`Bitrix24\SDK\Services\Main\Result\ApplicationInfoResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Main/Result/ApplicationInfoResult.php)| +|`–`|[user.admin](https://training.bitrix24.com/rest_help/general/user_admin.php)|Checks if a current user has permissions to manage application parameters.|[`Bitrix24\SDK\Services\Main\Service\Main::isCurrentUserHasAdminRights`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Main/Service/Main.php#L246-L249)
Return type
[`Bitrix24\SDK\Services\Main\Result\IsUserAdminResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Main/Result/IsUserAdminResult.php)| +|`catalog`|[catalog.catalog.get](https://training.bitrix24.com/rest_help/catalog/catalog/catalog_catalog_get.php)|The method gets field values of commercial catalog by ID.|[`Bitrix24\SDK\Services\Catalog\Catalog\Service\Catalog::get`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Catalog/Catalog/Service/Catalog.php#L41-L44)
Return type
[`Bitrix24\SDK\Services\Catalog\Catalog\Result\CatalogResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Catalog/Catalog/Result/CatalogResult.php)| +|`catalog`|[catalog.catalog.list](https://training.bitrix24.com/rest_help/catalog/catalog/catalog_catalog_list.php)|The method gets field value of commercial catalog product list|[`Bitrix24\SDK\Services\Catalog\Catalog\Service\Catalog::list`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Catalog/Catalog/Service/Catalog.php#L58-L66)
Return type
[`Bitrix24\SDK\Services\Catalog\Catalog\Result\CatalogsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Catalog/Catalog/Result/CatalogsResult.php)| +|`catalog`|[catalog.catalog.getFields](https://training.bitrix24.com/rest_help/catalog/catalog/catalog_catalog_getfields.php)|Retrieves the fields for the catalog.|[`Bitrix24\SDK\Services\Catalog\Catalog\Service\Catalog::fields`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Catalog/Catalog/Service/Catalog.php#L81-L84)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/FieldsResult.php)| +|`catalog`|[catalog.product.get](https://training.bitrix24.com/rest_help/catalog/product/catalog_product_get.php)|The method gets field value of commercial catalog product by ID.|[`Bitrix24\SDK\Services\Catalog\Product\Service\Product::get`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Catalog/Product/Service/Product.php#L55-L58)
Return type
[`Bitrix24\SDK\Services\Catalog\Product\Result\ProductResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Catalog/Product/Result/ProductResult.php)| +|`catalog`|[catalog.product.add](https://training.bitrix24.com/rest_help/catalog/product/catalog_product_add.php)|The method adds a commercial catalog product.|[`Bitrix24\SDK\Services\Catalog\Product\Service\Product::add`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Catalog/Product/Service/Product.php#L72-L78)
Return type
[`Bitrix24\SDK\Services\Catalog\Product\Result\ProductResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Catalog/Product/Result/ProductResult.php)| +|`catalog`|[catalog.product.delete](https://training.bitrix24.com/rest_help/catalog/product/catalog_product_delete.php)|The method deletes commercial catalog product by ID|[`Bitrix24\SDK\Services\Catalog\Product\Service\Product::delete`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Catalog/Product/Service/Product.php#L92-L95)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/DeletedItemResult.php)| +|`catalog`|[catalog.product.list](https://training.bitrix24.com/rest_help/catalog/product/catalog_product_list.php)|The method gets list of commercial catalog products by filter.|[`Bitrix24\SDK\Services\Catalog\Product\Service\Product::list`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Catalog/Product/Service/Product.php#L109-L117)
Return type
[`Bitrix24\SDK\Services\Catalog\Product\Result\ProductsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Catalog/Product/Result/ProductsResult.php)| +|`catalog`|[catalog.product.getFieldsByFilter](https://training.bitrix24.com/rest_help/catalog/product/catalog_product_getfieldsbyfilter.php)|The method returns commercial catalog product fields by filter.|[`Bitrix24\SDK\Services\Catalog\Product\Service\Product::fieldsByFilter`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Catalog/Product/Service/Product.php#L131-L142)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/FieldsResult.php)| +|`crm`|[crm.settings.mode.get](https://training.bitrix24.com/rest_help/crm/mode/crm_settings_mode_get.php)|The method returns current settings for CRM mode|[`Bitrix24\SDK\Services\CRM\Settings\Service\Settings::modeGet`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Settings/Service/Settings.php#L37-L40)
Return type
[`Bitrix24\SDK\Services\CRM\Settings\Result\SettingsModeResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Settings/Result/SettingsModeResult.php)| +|`crm`|[crm.userfield.types](https://training.bitrix24.com/rest_help/crm/userfields/crm_userfield_types.php)|Returns list of user field types.|[`Bitrix24\SDK\Services\CRM\Userfield\Service\Userfield::types`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Userfield/Service/Userfield.php#L41-L44)
Return type
[`Bitrix24\SDK\Services\CRM\Userfield\Result\UserfieldTypesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Userfield/Result/UserfieldTypesResult.php)| +|`crm`|[crm.userfield.fields](https://training.bitrix24.com/rest_help/crm/userfields/crm_userfield_fields.php)|Returns field description for user fields.|[`Bitrix24\SDK\Services\CRM\Userfield\Service\Userfield::enumerationFields`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Userfield/Service/Userfield.php#L77-L80)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/FieldsResult.php)| +|`crm`|[crm.dealcategory.add](https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_add.php)|Add new deal category|[`Bitrix24\SDK\Services\CRM\Deal\Service\DealCategory::add`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Service/DealCategory.php#L55-L65)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/AddedItemResult.php)| +|`crm`|[crm.dealcategory.delete](https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_delete.php)|Delete deal category|[`Bitrix24\SDK\Services\CRM\Deal\Service\DealCategory::delete`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Service/DealCategory.php#L83-L93)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/DeletedItemResult.php)| +|`crm`|[crm.dealcategory.fields](https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_fields.php)|Returns field description for deal categories|[`Bitrix24\SDK\Services\CRM\Deal\Service\DealCategory::fields`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Service/DealCategory.php#L109-L112)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/FieldsResult.php)| +|`crm`|[crm.dealcategory.default.get](https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_default_get.php)|he method reads settings for general deal category|[`Bitrix24\SDK\Services\CRM\Deal\Service\DealCategory::getDefaultCategorySettings`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Service/DealCategory.php#L127-L130)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealCategoryResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Result/DealCategoryResult.php)| +|`crm`|[crm.dealcategory.default.set](https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_default_set.php)|The method writes settings for general deal category.|[`Bitrix24\SDK\Services\CRM\Deal\Service\DealCategory::setDefaultCategorySettings`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Service/DealCategory.php#L150-L153)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/UpdatedItemResult.php)| +|`crm`|[crm.dealcategory.get](https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_get.php)|Returns deal category by the ID|[`Bitrix24\SDK\Services\CRM\Deal\Service\DealCategory::get`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Service/DealCategory.php#L172-L182)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealCategoryResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Result/DealCategoryResult.php)| +|`crm`|[crm.dealcategory.list](https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_status.php)|Returns directory type ID for storage deal categories by the ID.|[`Bitrix24\SDK\Services\CRM\Deal\Service\DealCategory::getStatus`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Service/DealCategory.php#L234-L244)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealCategoryStatusResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Result/DealCategoryStatusResult.php)| +|`crm`|[crm.dealcategory.update](https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_update.php)|Updates an existing category.|[`Bitrix24\SDK\Services\CRM\Deal\Service\DealCategory::update`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Service/DealCategory.php#L269-L280)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/UpdatedItemResult.php)| +|`crm`|[crm.dealcategory.stage.list](https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_stage_list.php)|Returns list of deal stages for category by the ID. Equivalent to calling crm.status.list method with parameter ENTITY_ID equal to the result of calling crm.dealcategory.status method.|[`Bitrix24\SDK\Services\CRM\Deal\Service\DealCategoryStage::list`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Service/DealCategoryStage.php#L38-L48)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealCategoryStagesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Result/DealCategoryStagesResult.php)| +|`crm`|[crm.deal.add](https://training.bitrix24.com/rest_help/crm/deals/crm_deal_add.php)|Add new deal|[`Bitrix24\SDK\Services\CRM\Deal\Service\Deal::add`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Service/Deal.php#L105-L116)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/AddedItemResult.php)

⚡️Batch methods:
  • `Bitrix24\SDK\Services\CRM\Deal\Service\Batch::add`
    Return type: `Generator`
| +|`crm`|[crm.deal.delete](https://training.bitrix24.com/rest_help/crm/deals/crm_deal_delete.php)|Delete deal|[`Bitrix24\SDK\Services\CRM\Deal\Service\Deal::delete`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Service/Deal.php#L134-L144)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/DeletedItemResult.php)

⚡️Batch methods:
  • `Bitrix24\SDK\Services\CRM\Deal\Service\Batch::delete`
    Return type: `Generator`
| +|`crm`|[crm.deal.fields](https://training.bitrix24.com/rest_help/crm/deals/crm_deal_get.php)|Get deal by id|[`Bitrix24\SDK\Services\CRM\Deal\Service\Deal::get`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Service/Deal.php#L181-L184)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Result/DealResult.php)| +|`crm`|[crm.deal.list](https://training.bitrix24.com/rest_help/crm/deals/crm_deal_list.php)|Get deal list by filter|[`Bitrix24\SDK\Services\CRM\Deal\Service\Deal::list`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Service/Deal.php#L205-L218)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Result/DealsResult.php)

⚡️Batch methods:
  • `Bitrix24\SDK\Services\CRM\Deal\Service\Batch::list`
    Return type: `Generator|array`
| +|`crm`|[crm.deal.update](https://training.bitrix24.com/rest_help/crm/deals/crm_deal_update.php)|Update deal list by filter|[`Bitrix24\SDK\Services\CRM\Deal\Service\Deal::update`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Service/Deal.php#L277-L289)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/UpdatedItemResult.php)

⚡️Batch methods:
  • `Bitrix24\SDK\Services\CRM\Deal\Service\Batch::update`
    Return type: `Generator`
| +|`crm`|[crm.deal.productrows.get](https://training.bitrix24.com/rest_help/crm/deals/crm_deal_productrows_get.php)|Returns products inside the specified deal.|[`Bitrix24\SDK\Services\CRM\Deal\Service\DealProductRows::get`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Service/DealProductRows.php#L45-L68)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealProductRowItemsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php)| +|`crm`|[crm.deal.productrows.set](https://training.bitrix24.com/rest_help/crm/deals/crm_deal_productrows_set.php)|Creates or updates product entries inside the specified deal.|[`Bitrix24\SDK\Services\CRM\Deal\Service\DealProductRows::set`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Service/DealProductRows.php#L108-L119)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/UpdatedItemResult.php)| +|`crm`|[crm.deal.userfield.list](https://training.bitrix24.com/rest_help/crm/deals/crm_deal_userfield_list.php)|Returns list of user deal fields by filter.|[`Bitrix24\SDK\Services\CRM\Deal\Service\DealUserfield::list`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Service/DealUserfield.php#L87-L98)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealUserfieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Result/DealUserfieldsResult.php)| +|`crm`|[crm.deal.userfield.add](https://training.bitrix24.com/rest_help/crm/deals/crm_deal_userfield_add.php)|Created new user field for deals.|[`Bitrix24\SDK\Services\CRM\Deal\Service\DealUserfield::add`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Service/DealUserfield.php#L139-L159)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/AddedItemResult.php)| +|`crm`|[crm.deal.userfield.delete](https://training.bitrix24.com/rest_help/crm/deals/crm_deal_userfield_delete.php)|Deleted userfield for deals|[`Bitrix24\SDK\Services\CRM\Deal\Service\DealUserfield::delete`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Service/DealUserfield.php#L177-L187)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/DeletedItemResult.php)| +|`crm`|[crm.deal.userfield.get](https://training.bitrix24.com/rest_help/crm/deals/crm_deal_userfield_get.php)|Returns a userfield for deal by ID.|[`Bitrix24\SDK\Services\CRM\Deal\Service\DealUserfield::get`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Service/DealUserfield.php#L204-L214)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealUserfieldResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Result/DealUserfieldResult.php)| +|`crm`|[crm.deal.userfield.update](https://training.bitrix24.com/rest_help/crm/deals/crm_deal_userfield_update.php)|Updates an existing user field for deals.|[`Bitrix24\SDK\Services\CRM\Deal\Service\DealUserfield::update`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Service/DealUserfield.php#L232-L243)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/UpdatedItemResult.php)| +|`crm`|[crm.deal.contact.add](https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_stage_list.php)|Adds contact to specified deal.|[`Bitrix24\SDK\Services\CRM\Deal\Service\DealContact::add`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Service/DealContact.php#L49-L64)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/AddedItemResult.php)| +|`crm`|[crm.deal.contact.fields](https://training.bitrix24.com/rest_help/crm/deals/crm_deal_contact_fields.php)|Returns field descriptions for the deal-contact link used by methods of family crm.deal.contact.*|[`Bitrix24\SDK\Services\CRM\Deal\Service\DealContact::fields`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Service/DealContact.php#L78-L81)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/FieldsResult.php)| +|`crm`|[crm.deal.contact.items.get](https://training.bitrix24.com/rest_help/crm/deals/crm_deal_contact_items_get.php)|Returns a set of contacts, associated with the specified deal.|[`Bitrix24\SDK\Services\CRM\Deal\Service\DealContact::itemsGet`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Service/DealContact.php#L99-L109)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealContactItemsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Result/DealContactItemsResult.php)| +|`crm`|[crm.deal.contact.items.delete](https://training.bitrix24.com/rest_help/crm/deals/crm_deal_contact_items_delete.php)|Clears a set of contacts, associated with the specified deal.|[`Bitrix24\SDK\Services\CRM\Deal\Service\DealContact::itemsDelete`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Service/DealContact.php#L127-L137)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/DeletedItemResult.php)| +|`crm`|[crm.deal.contact.items.set](https://training.bitrix24.com/rest_help/crm/deals/crm_deal_contact_items_set.php)|Set a set of contacts, associated with the specified seal.|[`Bitrix24\SDK\Services\CRM\Deal\Service\DealContact::itemsSet`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Service/DealContact.php#L160-L171)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/UpdatedItemResult.php)| +|`crm`|[crm.deal.contact.delete](https://training.bitrix24.com/rest_help/crm/deals/crm_deal_contact_items_set.php)|Deletes contact from a specified deal|[`Bitrix24\SDK\Services\CRM\Deal\Service\DealContact::delete`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Deal/Service/DealContact.php#L190-L203)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/DeletedItemResult.php)| +|`crm`|[crm.contact.add](https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_add.php)|Creates a new contact.|[`Bitrix24\SDK\Services\CRM\Contact\Service\Contact::add`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Contact/Service/Contact.php#L117-L128)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/AddedItemResult.php)

⚡️Batch methods:
  • `Bitrix24\SDK\Services\CRM\Contact\Service\Batch::add`
    Return type: `Generator`
| +|`crm`|[crm.contact.delete](https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_delete.php)|Delete a contact.|[`Bitrix24\SDK\Services\CRM\Contact\Service\Contact::delete`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Contact/Service/Contact.php#L146-L156)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/DeletedItemResult.php)

⚡️Batch methods:
  • `Bitrix24\SDK\Services\CRM\Contact\Service\Batch::delete`
    Return type: `Generator`
| +|`crm`|[crm.contact.fields](https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_fields.php)|Returns the description of contact|[`Bitrix24\SDK\Services\CRM\Contact\Service\Contact::fields`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Contact/Service/Contact.php#L172-L175)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/FieldsResult.php)| +|`crm`|[crm.contact.get](https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_get.php)|Returns a contact by the specified contact ID|[`Bitrix24\SDK\Services\CRM\Contact\Service\Contact::get`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Contact/Service/Contact.php#L193-L203)
Return type
[`Bitrix24\SDK\Services\CRM\Contact\Result\ContactResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Contact/Result/ContactResult.php)| +|`crm`|[crm.contact.list](https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_list.php)|Returns a list of contacts selected by the filter specified as the parameter. |[`Bitrix24\SDK\Services\CRM\Contact\Service\Contact::list`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Contact/Service/Contact.php#L321-L334)
Return type
[`Bitrix24\SDK\Services\CRM\Contact\Result\ContactsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Contact/Result/ContactsResult.php)

⚡️Batch methods:
  • `Bitrix24\SDK\Services\CRM\Contact\Service\Batch::list`
    Return type: `Generator`
| +|`crm`|[crm.contact.update](https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_update.php)|Update contact by id|[`Bitrix24\SDK\Services\CRM\Contact\Service\Contact::update`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Contact/Service/Contact.php#L401-L413)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/UpdatedItemResult.php)

⚡️Batch methods:
  • `Bitrix24\SDK\Services\CRM\Contact\Service\Batch::update`
    Return type: `Generator`
| +|`crm`|[crm.contact.userfield.list](https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_userfield_list.php)|Returns list of user custom fields for contacts by filter. Prints information about these fields, only identifier and without a title assigned to the field by the user. |[`Bitrix24\SDK\Services\CRM\Contact\Service\ContactUserfield::list`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Contact/Service/ContactUserfield.php#L85-L96)
Return type
[`Bitrix24\SDK\Services\CRM\Contact\Result\ContactUserfieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Contact/Result/ContactUserfieldsResult.php)| +|`crm`|[crm.contact.userfield.add](https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_userfield_add.php)|Creates a new user field for contacts.|[`Bitrix24\SDK\Services\CRM\Contact\Service\ContactUserfield::add`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Contact/Service/ContactUserfield.php#L137-L157)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/AddedItemResult.php)| +|`crm`|[crm.contact.userfield.delete](https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_userfield_delete.php)|Delete a user by Id|[`Bitrix24\SDK\Services\CRM\Contact\Service\ContactUserfield::delete`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Contact/Service/ContactUserfield.php#L175-L185)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/DeletedItemResult.php)| +|`crm`|[crm.contact.userfield.get](https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_userfield_get.php)|Get a user by Id|[`Bitrix24\SDK\Services\CRM\Contact\Service\ContactUserfield::get`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Contact/Service/ContactUserfield.php#L202-L212)
Return type
[`Bitrix24\SDK\Services\CRM\Contact\Result\ContactUserfieldResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Contact/Result/ContactUserfieldResult.php)| +|`crm`|[crm.contact.userfield.update](https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_userfield_update.php)|Update a user by Id|[`Bitrix24\SDK\Services\CRM\Contact\Service\ContactUserfield::update`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Contact/Service/ContactUserfield.php#L230-L241)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/UpdatedItemResult.php)| +|`crm`|[crm.activity.add](https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_add.php)|Creates and adds a new activity.|[`Bitrix24\SDK\Services\CRM\Activity\Service\Activity::add`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Activity/Service/Activity.php#L110-L120)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/AddedItemResult.php)

⚡️Batch methods:
  • `Bitrix24\SDK\Services\CRM\Activity\Service\Batch::add`
    Return type: `Generator, Bitrix24\SDK\Core\Result\AddedItemBatchResult, mixed, mixed>`
| +|`crm`|[crm.activity.delete](https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_delete.php)|Deletes the specified activity and all the associated objects.|[`Bitrix24\SDK\Services\CRM\Activity\Service\Activity::delete`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Activity/Service/Activity.php#L138-L148)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/DeletedItemResult.php)

⚡️Batch methods:
  • `Bitrix24\SDK\Services\CRM\Activity\Service\Batch::delete`
    Return type: `Generator, Bitrix24\SDK\Core\Result\DeletedItemBatchResult, mixed, mixed>`
| +|`crm`|[crm.activity.fields](https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_fields.php)|Returns the description of activity fields|[`Bitrix24\SDK\Services\CRM\Activity\Service\Activity::fields`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Activity/Service/Activity.php#L164-L167)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/FieldsResult.php)| +|`crm`|[crm.activity.get](https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_get.php)|Returns activity by the specified activity ID|[`Bitrix24\SDK\Services\CRM\Activity\Service\Activity::get`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Activity/Service/Activity.php#L185-L195)
Return type
[`Bitrix24\SDK\Services\CRM\Activity\Result\ActivityResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Activity/Result/ActivityResult.php)| +|`crm`|[crm.activity.list](https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_list.php)|Returns a list of activity selected by the filter specified as the parameter. See the example for the filter notation.|[`Bitrix24\SDK\Services\CRM\Activity\Service\Activity::list`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Activity/Service/Activity.php#L306-L319)
Return type
[`Bitrix24\SDK\Services\CRM\Activity\Result\ActivitiesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Activity/Result/ActivitiesResult.php)

⚡️Batch methods:
  • `Bitrix24\SDK\Services\CRM\Activity\ReadModel\VoximplantFetcher::getList`
    Return type: `Generator, Bitrix24\SDK\Services\CRM\Activity\Result\ActivityItemResult, mixed, mixed>`
  • `Bitrix24\SDK\Services\CRM\Activity\ReadModel\WebFormFetcher::getList`
    Return type: `Generator, Bitrix24\SDK\Services\CRM\Activity\Result\WebForm\WebFormActivityItemResult, mixed, mixed>`
  • `Bitrix24\SDK\Services\CRM\Activity\ReadModel\OpenLineFetcher::getList`
    Return type: `Generator, Bitrix24\SDK\Services\CRM\Activity\Result\OpenLine\OpenLineActivityItemResult, mixed, mixed>`
  • `Bitrix24\SDK\Services\CRM\Activity\ReadModel\EmailFetcher::getList`
    Return type: `Generator, Bitrix24\SDK\Services\CRM\Activity\Result\Email\EmailActivityItemResult, mixed, mixed>`
  • `Bitrix24\SDK\Services\CRM\Activity\Service\Batch::list`
    Return type: `Generator, Bitrix24\SDK\Services\CRM\Activity\Result\ActivityItemResult, mixed, mixed>`
| +|`crm`|[crm.activity.update](https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_update.php)|Updates the specified (existing) activity.|[`Bitrix24\SDK\Services\CRM\Activity\Service\Activity::update`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Activity/Service/Activity.php#L382-L393)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/UpdatedItemResult.php)| +|`crm`|[crm.product.add](https://training.bitrix24.com/rest_help/crm/products/crm_product_add.php)|Add new product|[`Bitrix24\SDK\Services\CRM\Product\Service\Product::add`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Product/Service/Product.php#L87-L97)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/AddedItemResult.php)

⚡️Batch methods:
  • `Bitrix24\SDK\Services\CRM\Product\Service\Batch::add`
    Return type: `Generator`
| +|`crm`|[crm.product.delete](https://training.bitrix24.com/rest_help/crm/products/crm_product_delete.php)|Delete product by id|[`Bitrix24\SDK\Services\CRM\Product\Service\Product::delete`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Product/Service/Product.php#L115-L125)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/DeletedItemResult.php)| +|`crm`|[crm.product.get](https://training.bitrix24.com/rest_help/crm/products/crm_product_get.php)|Returns a product by the product id.|[`Bitrix24\SDK\Services\CRM\Product\Service\Product::get`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Product/Service/Product.php#L143-L146)
Return type
[`Bitrix24\SDK\Services\CRM\Product\Result\ProductResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Product/Result/ProductResult.php)| +|`crm`|[crm.product.fields](https://training.bitrix24.com/rest_help/crm/products/crm_product_fields.php)|Returns the description of the product fields, including user fields.|[`Bitrix24\SDK\Services\CRM\Product\Service\Product::fields`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Product/Service/Product.php#L162-L165)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/FieldsResult.php)| +|`crm`|[crm.product.list](https://training.bitrix24.com/rest_help/crm/products/crm_product_list.php)|Get list of product items.|[`Bitrix24\SDK\Services\CRM\Product\Service\Product::list`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Product/Service/Product.php#L186-L199)
Return type
[`Bitrix24\SDK\Services\CRM\Product\Result\ProductsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Product/Result/ProductsResult.php)

⚡️Batch methods:
  • `Bitrix24\SDK\Services\CRM\Product\Service\Batch::list`
    Return type: `Generator`
| +|`crm`|[crm.product.update](https://training.bitrix24.com/rest_help/crm/products/crm_product_update.php)|Updates the specified (existing) product.|[`Bitrix24\SDK\Services\CRM\Product\Service\Product::update`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Product/Service/Product.php#L240-L251)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/UpdatedItemResult.php)| +|`crm`|[crm.lead.add](https://training.bitrix24.com/rest_help/crm/leads/crm_lead_add.php)|Method adds new lead|[`Bitrix24\SDK\Services\CRM\Lead\Service\Lead::add`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Lead/Service/Lead.php#L124-L135)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/AddedItemResult.php)

⚡️Batch methods:
  • `Bitrix24\SDK\Services\CRM\Lead\Service\Batch::add`
    Return type: `Generator`
| +|`crm`|[crm.lead.delete](https://training.bitrix24.com/rest_help/crm/leads/crm_lead_delete.php)|Deletes the specified lead and all the associated objects.|[`Bitrix24\SDK\Services\CRM\Lead\Service\Lead::delete`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Lead/Service/Lead.php#L153-L163)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/DeletedItemResult.php)

⚡️Batch methods:
  • `Bitrix24\SDK\Services\CRM\Lead\Service\Batch::delete`
    Return type: `Generator`
| +|`crm`|[crm.lead.fields](https://training.bitrix24.com/rest_help/crm/leads/crm_lead_fields.php)|Returns the description of the lead fields, including user fields.|[`Bitrix24\SDK\Services\CRM\Lead\Service\Lead::fields`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Lead/Service/Lead.php#L179-L182)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/FieldsResult.php)| +|`crm`|[crm.lead.get](https://training.bitrix24.com/rest_help/crm/leads/crm_lead_get.php)|Returns a lead by the lead ID.|[`Bitrix24\SDK\Services\CRM\Lead\Service\Lead::get`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Lead/Service/Lead.php#L200-L203)
Return type
[`Bitrix24\SDK\Services\CRM\Lead\Result\LeadResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Lead/Result/LeadResult.php)| +|`crm`|[crm.lead.list](https://training.bitrix24.com/rest_help/crm/leads/crm_lead_list.php)|Get list of lead items.|[`Bitrix24\SDK\Services\CRM\Lead\Service\Lead::list`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Lead/Service/Lead.php#L224-L237)
Return type
[`Bitrix24\SDK\Services\CRM\Lead\Result\LeadsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Lead/Result/LeadsResult.php)

⚡️Batch methods:
  • `Bitrix24\SDK\Services\CRM\Lead\Service\Batch::list`
    Return type: `Generator`
| +|`crm`|[crm.lead.update](https://training.bitrix24.com/rest_help/crm/leads/crm_lead_update.php)|Updates the specified (existing) lead.|[`Bitrix24\SDK\Services\CRM\Lead\Service\Lead::update`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Lead/Service/Lead.php#L316-L328)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/UpdatedItemResult.php)| +|`crm`|[crm.item.add](https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_add.php)|Method creates new SPA item with entityTypeId.|[`Bitrix24\SDK\Services\CRM\Item\Service\Item::add`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Item/Service/Item.php#L58-L69)
Return type
[`Bitrix24\SDK\Services\CRM\Item\Result\ItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Item/Result/ItemResult.php)

⚡️Batch methods:
  • `Bitrix24\SDK\Services\CRM\Item\Service\Batch::add`
    Return type: `Generator`
| +|`crm`|[crm.item.delete](https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_delete.php)|Deletes item with id for SPA with entityTypeId.|[`Bitrix24\SDK\Services\CRM\Item\Service\Item::delete`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Item/Service/Item.php#L88-L95)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/DeletedItemResult.php)| +|`crm`|[crm.item.fields](https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_fields.php)|Returns the fields data with entityTypeId.|[`Bitrix24\SDK\Services\CRM\Item\Service\Item::fields`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Item/Service/Item.php#L112-L115)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/FieldsResult.php)| +|`crm`|[crm.item.get](https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_get.php)|Returns item data with id for SPA with entityTypeId.|[`Bitrix24\SDK\Services\CRM\Item\Service\Item::get`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Item/Service/Item.php#L130-L133)
Return type
[`Bitrix24\SDK\Services\CRM\Item\Result\ItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Item/Result/ItemResult.php)| +|`crm`|[crm.item.list](https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_list.php)|Returns array with SPA items with entityTypeId|[`Bitrix24\SDK\Services\CRM\Item\Service\Item::list`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Item/Service/Item.php#L148-L162)
Return type
[`Bitrix24\SDK\Services\CRM\Item\Result\ItemsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Item/Result/ItemsResult.php)

⚡️Batch methods:
  • `Bitrix24\SDK\Services\CRM\Item\Service\Batch::list`
    Return type: `Generator`
| +|`crm`|[crm.item.update](https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_update.php)|Updates the specified (existing) item.|[`Bitrix24\SDK\Services\CRM\Item\Service\Item::update`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Item/Service/Item.php#L177-L189)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/UpdatedItemResult.php)| +|`crm`|[crm.duplicate.findbycomm](https://training.bitrix24.com/rest_help/crm/auxiliary/duplicates/crm.duplicate.findbycomm.php)|The method returns IDs for leads, contacts or companies that contain the specified phone numbers or e-mails.|[`Bitrix24\SDK\Services\CRM\Duplicates\Service\Duplicate::findByEmail`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Duplicates/Service/Duplicate.php#L61-L69)
Return type
[`Bitrix24\SDK\Services\CRM\Duplicates\Result\DuplicateResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/CRM/Duplicates/Result/DuplicateResult.php)| +|`bizproc`|[bizproc.activity.log](https://training.bitrix24.com/rest_help/workflows/app_activities/bizproc_activity_list.php)|This method records data in the workflow log.|[`Bitrix24\SDK\Services\Workflows\Activity\Service\Activity::log`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Activity/Service/Activity.php#L55-L61)
Return type
[`Bitrix24\SDK\Services\Workflows\Activity\Result\AddedMessageToLogResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Activity/Result/AddedMessageToLogResult.php)| +|`bizproc`|[bizproc.activity.list](https://training.bitrix24.com/rest_help/workflows/app_activities/bizproc_activity_list.php)|This method returns list of activities, installed by the application.|[`Bitrix24\SDK\Services\Workflows\Activity\Service\Activity::list`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Activity/Service/Activity.php#L75-L78)
Return type
[`Bitrix24\SDK\Services\Workflows\Activity\Result\WorkflowActivitiesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Activity/Result/WorkflowActivitiesResult.php)| +|`bizproc`|[bizproc.activity.add](https://training.bitrix24.com/rest_help/workflows/app_activities/bizproc_activity_add.php)|Adds new activity to a workflow.|[`Bitrix24\SDK\Services\Workflows\Activity\Service\Activity::add`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Activity/Service/Activity.php#L105-L132)
Return type
[`Bitrix24\SDK\Services\Workflows\Activity\Result\AddedActivityResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Activity/Result/AddedActivityResult.php)| +|`bizproc`|[bizproc.activity.delete](https://training.bitrix24.com/rest_help/workflows/app_activities/bizproc_activity_delete.php)|This method deletes an activity.|[`Bitrix24\SDK\Services\Workflows\Activity\Service\Activity::delete`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Activity/Service/Activity.php#L147-L153)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/DeletedItemResult.php)| +|`bizproc`|[bizproc.activity.update](https://training.bitrix24.com/rest_help/workflows/app_activities/bizproc_activity_update.php)|This method allows to update activity fields. Method parameters are similar to bizproc.activity.add.|[`Bitrix24\SDK\Services\Workflows\Activity\Service\Activity::update`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Activity/Service/Activity.php#L180-L234)
Return type
[`Bitrix24\SDK\Services\Workflows\Activity\Result\UpdateActivityResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Activity/Result/UpdateActivityResult.php)| +|`bizproc`|[bizproc.workflow.template.add](https://training.bitrix24.com/rest_help/workflows/wirkflow_template/bizproc_workflow_template_add.php)|Add a workflow template, requires administrator access permissions|[`Bitrix24\SDK\Services\Workflows\Template\Service\Template::add`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Template/Service/Template.php#L57-L72)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/AddedItemResult.php)| +|`bizproc`|[bizproc.workflow.template.update](https://training.bitrix24.com/rest_help/workflows/wirkflow_template/bizproc_workflow_template_update.php)|Update workflow template|[`Bitrix24\SDK\Services\Workflows\Template\Service\Template::update`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Template/Service/Template.php#L92-L127)
Return type
[``](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/)| +|`bizproc`|[bizproc.workflow.template.delete](https://training.bitrix24.com/rest_help/workflows/wirkflow_template/bizproc_workflow_template_delete.php)|The method deletes workflow template. Requires the administrator access permissions.|[`Bitrix24\SDK\Services\Workflows\Template\Service\Template::delete`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Template/Service/Template.php#L145-L150)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/DeletedItemResult.php)| +|`bizproc`|[bizproc.workflow.template.list](https://training.bitrix24.com/rest_help/workflows/wirkflow_template/bizproc_workflow_template_list.php)|The method bizproc.workflow.template.list returns list of workflow templates, specified for a site. |[`Bitrix24\SDK\Services\Workflows\Template\Service\Template::list`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Template/Service/Template.php#L164-L177)
Return type
[`Bitrix24\SDK\Services\Workflows\Template\Result\WorkflowTemplatesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Template/Result/WorkflowTemplatesResult.php)| +|`bizproc`|[bizproc.robot.add](https://training.bitrix24.com/rest_help/workflows/app_automation_rules/bizproc_robot_add.php)|Registers new automation rule.|[`Bitrix24\SDK\Services\Workflows\Robot\Service\Robot::add`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Robot/Service/Robot.php#L57-L78)
Return type
[`Bitrix24\SDK\Services\Workflows\Robot\Result\AddedRobotResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Robot/Result/AddedRobotResult.php)| +|`bizproc`|[bizproc.robot.list](https://training.bitrix24.com/rest_help/workflows/app_automation_rules/bizproc_robot_list.php)|This method returns list of automation rules, registered by the application.|[`Bitrix24\SDK\Services\Workflows\Robot\Service\Robot::list`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Robot/Service/Robot.php#L92-L95)
Return type
[`Bitrix24\SDK\Services\Workflows\Robot\Result\WorkflowRobotsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Robot/Result/WorkflowRobotsResult.php)| +|`bizproc`|[bizproc.robot.delete](https://training.bitrix24.com/rest_help/workflows/app_automation_rules/bizproc_robot_delete.php)|This method deletes registered automation rule.|[`Bitrix24\SDK\Services\Workflows\Robot\Service\Robot::delete`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Robot/Service/Robot.php#L110-L116)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/DeletedItemResult.php)| +|`bizproc`|[bizproc.robot.update](https://training.bitrix24.com/rest_help/workflows/app_automation_rules/bizproc_robot_update.php)|updates fields of automation rules|[`Bitrix24\SDK\Services\Workflows\Robot\Service\Robot::update`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Robot/Service/Robot.php#L133-L175)
Return type
[`Bitrix24\SDK\Services\Workflows\Robot\Result\UpdateRobotResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Robot/Result/UpdateRobotResult.php)| +|`bizproc`|[bizproc.workflow.kill](https://training.bitrix24.com/rest_help/workflows/workflow/bizproc_workflow_kill.php)|Deletes a launched workflow|[`Bitrix24\SDK\Services\Workflows\Workflow\Service\Workflow::kill`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Workflow/Service/Workflow.php#L52-L57)
Return type
[`Bitrix24\SDK\Services\Workflows\Workflow\Result\WorkflowKillResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Workflow/Result/WorkflowKillResult.php)| +|`bizproc`|[bizproc.workflow.terminate](https://training.bitrix24.com/rest_help/workflows/workflow/bizproc_workflow_terminate.php)|Stops an active workflow.|[`Bitrix24\SDK\Services\Workflows\Workflow\Service\Workflow::terminate`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Workflow/Service/Workflow.php#L70-L76)
Return type
[`Bitrix24\SDK\Services\Workflows\Workflow\Result\WorkflowTerminationResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Workflow/Result/WorkflowTerminationResult.php)| +|`bizproc`|[bizproc.workflow.start](https://training.bitrix24.com/rest_help/workflows/workflow/bizproc_workflow_start.php)|Launches a workflow|[`Bitrix24\SDK\Services\Workflows\Workflow\Service\Workflow::start`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Workflow/Service/Workflow.php#L92-L144)
Return type
[`Bitrix24\SDK\Services\Workflows\Workflow\Result\WorkflowInstanceStartResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Workflow/Result/WorkflowInstanceStartResult.php)| +|`bizproc`|[bizproc.workflow.instances](https://training.bitrix24.com/rest_help/workflows/workflow/bizproc_workflow_instances.php)|returns list of launched workflows|[`Bitrix24\SDK\Services\Workflows\Workflow\Service\Workflow::instances`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Workflow/Service/Workflow.php#L159-L174)
Return type
[`Bitrix24\SDK\Services\Workflows\Workflow\Result\WorkflowInstancesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Workflow/Result/WorkflowInstancesResult.php)| +|`bizproc`|[bizproc.task.complete](https://training.bitrix24.com/rest_help/workflows/workflows_tasks/bizproc_task_complete.php)|Complete workflow task|[`Bitrix24\SDK\Services\Workflows\Task\Service\Task::complete`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Task/Service/Task.php#L63-L71)
Return type
[`Bitrix24\SDK\Services\Workflows\Task\Result\WorkflowTaskCompleteResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Task/Result/WorkflowTaskCompleteResult.php)| +|`bizproc`|[bizproc.task.list](https://training.bitrix24.com/rest_help/workflows/workflows_tasks/bizproc_task_list.php)|List of workflow tasks|[`Bitrix24\SDK\Services\Workflows\Task\Service\Task::list`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Task/Service/Task.php#L133-L143)
Return type
[`Bitrix24\SDK\Services\Workflows\Task\Result\WorkflowTasksResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Task/Result/WorkflowTasksResult.php)| +|`bizproc`|[bizproc.event.send](https://training.bitrix24.com/rest_help/workflows/workflows_events/bizproc_event_send.php)|returns output parameters to an activity. Parameters are specified in the activity description.|[`Bitrix24\SDK\Services\Workflows\Event\Service\Event::send`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Event/Service/Event.php#L50-L64)
Return type
[`Bitrix24\SDK\Services\Workflows\Event\Result\EventSendResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Workflows/Event/Result/EventSendResult.php)| +|`user`|[user.fields](https://training.bitrix24.com/rest_help/users/user_fields.php)|Get user entity fields|[`Bitrix24\SDK\Services\User\Service\User::fields`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/User/Service/User.php#L43-L46)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/FieldsResult.php)| +|`user`|[user.current](https://training.bitrix24.com/rest_help/users/user_current.php)|Get current user|[`Bitrix24\SDK\Services\User\Service\User::current`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/User/Service/User.php#L59-L62)
Return type
[`Bitrix24\SDK\Services\User\Result\UserResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/User/Result/UserResult.php)| +|`user`|[user.add](https://training.bitrix24.com/rest_help/users/user_add.php)|Invites a user. Available only for users with invitation permissions, usually an administrator. Sends a standard account invitation to the user on success.|[`Bitrix24\SDK\Services\User\Service\User::add`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/User/Service/User.php#L77-L92)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/AddedItemResult.php)| +|`user`|[user.get](https://training.bitrix24.com/rest_help/users/user_get.php)|Get user by id|[`Bitrix24\SDK\Services\User\Service\User::get`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/User/Service/User.php#L104-L116)
Return type
[`Bitrix24\SDK\Services\User\Result\UsersResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/User/Result/UsersResult.php)| +|`user`|[user.update](https://training.bitrix24.com/rest_help/users/user_get.php)|Updates user information. Available only for users with invitation permissions.|[`Bitrix24\SDK\Services\User\Service\User::update`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/User/Service/User.php#L129-L137)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/UpdatedItemResult.php)| +|`user`|[user.search](https://training.bitrix24.com/rest_help/users/user_search.php)|This method is used to retrieve list of users with expedited personal data search.|[`Bitrix24\SDK\Services\User\Service\User::search`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/User/Service/User.php#L151-L154)
Return type
[`Bitrix24\SDK\Services\User\Result\UsersResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/User/Result/UsersResult.php)| +|`telephony`|[voximplant.user.deactivatePhone](https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_user_deactivatePhone.php)|This method disables an indicator of SIP-phone availability. Method checks the availability of the access permissions to modify users.|[`Bitrix24\SDK\Services\Telephony\Voximplant\User\Service\User::deactivatePhone`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/User/Service/User.php#L52-L57)
Return type
[`Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/UserInterfaceDialogCallResult.php)| +|`telephony`|[voximplant.user.activatePhone](https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_user_activatePhone.php)|This method raises the event of SIP-phone availability for an employee. Method checks the availability of the access permissions to modify users.|[`Bitrix24\SDK\Services\Telephony\Voximplant\User\Service\User::activatePhone`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/User/Service/User.php#L73-L78)
Return type
[`Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/UserInterfaceDialogCallResult.php)| +|`telephony`|[voximplant.user.get](https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_user_get.php)|This method returns user settings.|[`Bitrix24\SDK\Services\Telephony\Voximplant\User\Service\User::get`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/User/Service/User.php#L95-L102)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\User\Result\VoximplantUserSettingsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/User/Result/VoximplantUserSettingsResult.php)| +|`telephony`|[voximplant.url.get](https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_url_get.php)|Returns a set of links for browsing telephony scope pages.|[`Bitrix24\SDK\Services\Telephony\Voximplant\Url\Service\Url::get`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/Url/Service/Url.php#L50-L53)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\Url\Result\VoximplantPagesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/Url/Result/VoximplantPagesResult.php)| +|`telephony`|[voximplant.line.outgoing.sip.set](https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_line_outgoing_sip_set.php)|Sets the selected SIP line as an outgoing line by default.|[`Bitrix24\SDK\Services\Telephony\Voximplant\Line\Service\Line::outgoingSipSet`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/Line/Service/Line.php#L50-L55)
Return type
[`Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/UserInterfaceDialogCallResult.php)| +|`telephony`|[voximplant.line.get](https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_line_get.php)|Returns list of all of the available outgoing lines.|[`Bitrix24\SDK\Services\Telephony\Voximplant\Line\Service\Line::get`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/Line/Service/Line.php#L67-L70)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\Line\Result\VoximplantLinesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/Line/Result/VoximplantLinesResult.php)| +|`telephony`|[voximplant.line.outgoing.get](https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_line_outgoing_get.php)|Returns the currently selected line as an outgoing line by default.|[`Bitrix24\SDK\Services\Telephony\Voximplant\Line\Service\Line::outgoingGet`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/Line/Service/Line.php#L84-L87)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\Line\Result\VoximplantLineIdResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/Line/Result/VoximplantLineIdResult.php)| +|`telephony`|[voximplant.line.outgoing.set](https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_line_outgoing_set.php)|Sets the selected line as an outgoing line by default.|[`Bitrix24\SDK\Services\Telephony\Voximplant\Line\Service\Line::outgoingSet`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/Line/Service/Line.php#L103-L108)
Return type
[`Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/UserInterfaceDialogCallResult.php)| +|`telephony`|[voximplant.tts.voices.get](https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_tts_voices.get.php)|Returns an array of available voices for generation of speech in the format of voice ID => voice name.|[`Bitrix24\SDK\Services\Telephony\Voximplant\TTS\Voices\Service\Voices::get`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/TTS/Voices/Service/Voices.php#L52-L55)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\TTS\Voices\Result\VoximplantVoicesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/TTS/Voices/Result/VoximplantVoicesResult.php)| +|`telephony`|[voximplant.sip.connector.status](https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_sip_connector_status.php)|Returns the current status of the SIP Connector.|[`Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Service\Sip::getConnectorStatus`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/Sip/Service/Sip.php#L57-L60)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result\SipConnectorStatusResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/Sip/Result/SipConnectorStatusResult.php)| +|`telephony`|[voximplant.sip.add](https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_sip_add.php)|Сreates a new SIP line linked to the application. Once created, this line becomes an outbound line by default.|[`Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Service\Sip::add`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/Sip/Service/Sip.php#L74-L89)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result\SipLineAddedResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/Sip/Result/SipLineAddedResult.php)| +|`telephony`|[voximplant.sip.delete](https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_sip_delete.php)|Deletes the current SIP line (created by the application).|[`Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Service\Sip::delete`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/Sip/Service/Sip.php#L105-L110)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/DeletedItemResult.php)| +|`telephony`|[voximplant.sip.get](https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_sip_get.php)|Returns the list of all SIP lines created by the application. It is a list method.|[`Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Service\Sip::get`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/Sip/Service/Sip.php#L125-L128)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result\SipLinesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/Sip/Result/SipLinesResult.php)| +|`telephony`|[voximplant.sip.status](https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_sip_status.php)|Returns the current status of the SIP registration (for cloud hosted PBX only).|[`Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Service\Sip::status`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/Sip/Service/Sip.php#L145-L150)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result\SipLineStatusResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/Sip/Result/SipLineStatusResult.php)| +|`telephony`|[voximplant.sip.update](https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_sip_update.php)|Updates the existing SIP line (created by the application).|[`Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Service\Sip::update`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/Sip/Service/Sip.php#L165-L200)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/UpdatedItemResult.php)| +|`telephony`|[voximplant.infocall.startwithtext](https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_infocall_startwithtext.php)|method performs the call to the specified number with automatic voiceover of specified text|[`Bitrix24\SDK\Services\Telephony\Voximplant\InfoCall\Service\InfoCall::startWithText`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/InfoCall/Service/InfoCall.php#L56-L64)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\InfoCall\Result\VoximplantInfoCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/InfoCall/Result/VoximplantInfoCallResult.php)| +|`telephony`|[voximplant.infocall.startwithsound](https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_infocall_startwithsound.php)|Makes a call to the specified number with playback of .mp3 format file by URL.|[`Bitrix24\SDK\Services\Telephony\Voximplant\InfoCall\Service\InfoCall::startWithSound`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/InfoCall/Service/InfoCall.php#L71-L78)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\InfoCall\Result\VoximplantInfoCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Voximplant/InfoCall/Result/VoximplantInfoCallResult.php)| +|`telephony`|[telephony.call.attachTranscription](https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_call_attachtranscription.php)|The method adds a call transcript.|[`Bitrix24\SDK\Services\Telephony\Call\Service\Call::attachTranscription`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Call/Service/Call.php#L54-L76)
Return type
[`Bitrix24\SDK\Services\Telephony\Call\Result\TranscriptAttachedResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/Call/Result/TranscriptAttachedResult.php)| +|`telephony`|[telephony.externalCall.attachRecord](https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalCall_attachRecord.php)|This method connects a record to a finished call and to the call Activity.|[`Bitrix24\SDK\Services\Telephony\ExternalCall\Service\ExternalCall::attachCallRecordInBase64`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/ExternalCall/Service/ExternalCall.php#L96-L107)
Return type
[`Bitrix24\SDK\Services\Telephony\ExternalCall\Result\CallRecordFileUploadedResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/ExternalCall/Result/CallRecordFileUploadedResult.php)| +|`telephony`|[telephony.externalcall.register](https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_register.php)|Method registers a call in Bitrix24. For this purpose, it searches an object that corresponds to the number in CRM.|[`Bitrix24\SDK\Services\Telephony\ExternalCall\Service\ExternalCall::register`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/ExternalCall/Service/ExternalCall.php#L156-L188)
Return type
[`Bitrix24\SDK\Services\Telephony\ExternalCall\Result\ExternalCallRegisteredResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/ExternalCall/Result/ExternalCallRegisteredResult.php)| +|`telephony`|[telephony.externalCall.searchCrmEntities](https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalCall_searchCrmEntities.php)|This method allows to retrieve information about a client from CRM by a telephone number via single request.|[`Bitrix24\SDK\Services\Telephony\ExternalCall\Service\ExternalCall::searchCrmEntities`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/ExternalCall/Service/ExternalCall.php#L220-L226)
Return type
[`Bitrix24\SDK\Services\Telephony\ExternalCall\Result\SearchCrmEntitiesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/ExternalCall/Result/SearchCrmEntitiesResult.php)| +|`telephony`|[telephony.externalcall.finish](https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_finish.php)|This method allows to retrieve information about a client from CRM by a telephone number via single request.|[`Bitrix24\SDK\Services\Telephony\ExternalCall\Service\ExternalCall::finishForUserId`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/ExternalCall/Service/ExternalCall.php#L285-L308)
Return type
[`Bitrix24\SDK\Services\Telephony\ExternalCall\Result\ExternalCallFinishedResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/ExternalCall/Result/ExternalCallFinishedResult.php)| +|`telephony`|[telephony.externalcall.show](https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_show.php)|The method displays a call ID screen to the user.|[`Bitrix24\SDK\Services\Telephony\ExternalCall\Service\ExternalCall::show`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/ExternalCall/Service/ExternalCall.php#L324-L331)
Return type
[`Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/UserInterfaceDialogCallResult.php)| +|`telephony`|[telephony.externalcall.hide](https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_hide.php)| This method hides call information window.|[`Bitrix24\SDK\Services\Telephony\ExternalCall\Service\ExternalCall::hide`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/ExternalCall/Service/ExternalCall.php#L347-L354)
Return type
[`Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/UserInterfaceDialogCallResult.php)| +|`telephony`|[telephony.externalLine.add](https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalLine_add.php)|Method adds an external line|[`Bitrix24\SDK\Services\Telephony\ExternalLine\Service\ExternalLine::add`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/ExternalLine/Service/ExternalLine.php#L55-L62)
Return type
[`Bitrix24\SDK\Services\Telephony\ExternalLine\Result\ExternalLineAddedResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/ExternalLine/Result/ExternalLineAddedResult.php)| +|`telephony`|[telephony.externalLine.delete](https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalLine_delete.php)|Method for deleting an external line.|[`Bitrix24\SDK\Services\Telephony\ExternalLine\Service\ExternalLine::delete`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/ExternalLine/Service/ExternalLine.php#L76-L81)
Return type
[`Bitrix24\SDK\Core\Result\EmptyResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/EmptyResult.php)| +|`telephony`|[telephony.externalLine.get](https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalLine_delete.php)|Method allows to retrieve the list of external lines of an application.|[`Bitrix24\SDK\Services\Telephony\ExternalLine\Service\ExternalLine::get`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/ExternalLine/Service/ExternalLine.php#L95-L98)
Return type
[`Bitrix24\SDK\Services\Telephony\ExternalLine\Result\ExternalLinesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Telephony/ExternalLine/Result/ExternalLinesResult.php)| +|`im`|[im.notify.system.add](https://training.bitrix24.com/support/training/course/index.php?COURSE_ID=115&LESSON_ID=23904&LESSON_PATH=9691.9805.11585.23904)|Sending system notification|[`Bitrix24\SDK\Services\IM\Notify\Service\Notify::fromSystem`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/IM/Notify/Service/Notify.php#L44-L64)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/AddedItemResult.php)| +|`im`|[im.notify.personal.add](https://training.bitrix24.com/support/training/course/index.php?COURSE_ID=115&LESSON_ID=23904&LESSON_PATH=9691.9805.11585.23904)|Sending personal notification|[`Bitrix24\SDK\Services\IM\Notify\Service\Notify::fromPersonal`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/IM/Notify/Service/Notify.php#L71-L91)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/AddedItemResult.php)| +|`im`|[im.notify.delete](https://training.bitrix24.com/support/training/course/index.php?COURSE_ID=115&LESSON_ID=23906&LESSON_PATH=9691.9805.11585.23906)|Deleting notification|[`Bitrix24\SDK\Services\IM\Notify\Service\Notify::delete`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/IM/Notify/Service/Notify.php#L98-L112)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/DeletedItemResult.php)| +|`im`|[im.notify.read](https://training.bitrix24.com/support/training/course/index.php?COURSE_ID=115&LESSON_ID=23908&LESSON_PATH=9691.9805.11585.23908)|"Unread" the list of notifications, excluding CONFIRM notification type|[`Bitrix24\SDK\Services\IM\Notify\Service\Notify::markMessagesAsUnread`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/IM/Notify/Service/Notify.php#L156-L167)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/UpdatedItemResult.php)| +|`im`|[im.notify.confirm](https://training.bitrix24.com/support/training/course/index.php?COURSE_ID=115&LESSON_ID=23912&LESSON_PATH=9691.9805.11585.23912)|Interaction with notification buttons|[`Bitrix24\SDK\Services\IM\Notify\Service\Notify::confirm`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/IM/Notify/Service/Notify.php#L174-L186)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/UpdatedItemResult.php)| +|`im`|[im.notify.answer](https://training.bitrix24.com/support/training/course/index.php?COURSE_ID=115&LESSON_ID=23910&LESSON_PATH=9691.9805.11585.23910)|Response to notification, supporting quick reply|[`Bitrix24\SDK\Services\IM\Notify\Service\Notify::answer`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/IM/Notify/Service/Notify.php#L193-L205)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/UpdatedItemResult.php)| +|`userconsent`|[userconsent.consent.add](https://training.bitrix24.com/rest_help/userconsent/userconsent_consent_add.php)|Add the received user agreement consent|[`Bitrix24\SDK\Services\UserConsent\Service\UserConsent::add`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/UserConsent/Service/UserConsent.php#L40-L43)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Result/AddedItemResult.php)| +|`userconsent`|[userconsent.agreement.list](https://training.bitrix24.com/rest_help/userconsent/userconsent_consent_add.php)|Add the received user agreement consent|[`Bitrix24\SDK\Services\UserConsent\Service\UserConsentAgreement::list`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/UserConsent/Service/UserConsentAgreement.php#L39-L42)
Return type
[`Bitrix24\SDK\Services\UserConsent\Result\UserConsentAgreementsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/UserConsent/Result/UserConsentAgreementsResult.php)| +|`userconsent`|[userconsent.agreement.text](https://training.bitrix24.com/rest_help/userconsent/userconsent_agreement_text.php)|This method gets the agreement text|[`Bitrix24\SDK\Services\UserConsent\Service\UserConsentAgreement::text`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/UserConsent/Service/UserConsentAgreement.php#L54-L70)
Return type
[`Bitrix24\SDK\Services\UserConsent\Result\UserConsentAgreementTextResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/UserConsent/Result/UserConsentAgreementTextResult.php)| +|`imopenlines`|[imopenlines.network.join](https://training.bitrix24.com/support/training/course/?COURSE_ID=115&LESSON_ID=25016)|Connecting an open channel by code|[`Bitrix24\SDK\Services\IMOpenLines\Service\Network::join`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/IMOpenLines/Service/Network.php#L38-L48)
Return type
[`Bitrix24\SDK\Services\IMOpenLines\Result\JoinOpenLineResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/IMOpenLines/Result/JoinOpenLineResult.php)| +|`imopenlines`|[imopenlines.network.message.add](https://training.bitrix24.com/support/training/course/?COURSE_ID=115&LESSON_ID=25018&LESSON_PATH=9691.9833.20331.25014.25018)|Sending Open Channel message to selected user|[`Bitrix24\SDK\Services\IMOpenLines\Service\Network::messageAdd`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/IMOpenLines/Service/Network.php#L58-L80)
Return type
[`Bitrix24\SDK\Services\IMOpenLines\Result\AddedMessageItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/IMOpenLines/Result/AddedMessageItemResult.php)| +|`–`|[events](https://training.bitrix24.com/rest_help/general/events_method/events.php)|Displays events from the general list of events.|[`Bitrix24\SDK\Services\Main\Service\Event::list`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Main/Service/Event.php#L46-L54)
Return type
[`Bitrix24\SDK\Services\Main\Result\EventListResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Main/Result/EventListResult.php)| +|`–`|[event.bind](https://training.bitrix24.com/rest_help/general/events_method/event_bind.php)|Installs a new event handler.|[`Bitrix24\SDK\Services\Main\Service\Event::bind`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Main/Service/Event.php#L69-L85)
Return type
[`Bitrix24\SDK\Services\Main\Result\EventHandlerBindResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Main/Result/EventHandlerBindResult.php)| +|`–`|[event.unbind](https://training.bitrix24.com/rest_help/general/events_method/event_unbind.php)|Uninstalls a previously installed event handler.|[`Bitrix24\SDK\Services\Main\Service\Event::unbind`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Main/Service/Event.php#L100-L112)
Return type
[`Bitrix24\SDK\Services\Main\Result\EventHandlerUnbindResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Main/Result/EventHandlerUnbindResult.php)| +|`–`|[event.test](https://training.bitrix24.com/rest_help/rest_sum/test_handler.php)|Test events|[`Bitrix24\SDK\Services\Main\Service\Event::test`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Main/Service/Event.php#L125-L128)
Return type
[`Bitrix24\SDK\Core\Response\Response`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Core/Response/Response.php)| +|`–`|[event.get](https://training.bitrix24.com/rest_help/general/events_method/event_get.php)|Obtaining a list of registered event handlers.|[`Bitrix24\SDK\Services\Main\Service\Event::get`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Main/Service/Event.php#L142-L145)
Return type
[`Bitrix24\SDK\Services\Main\Result\EventHandlersResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Main/Result/EventHandlersResult.php)| +|`placement`|[userfieldtype.add](https://training.bitrix24.com/rest_help/application_embedding/user_field/userfieldtype_add.php)|Registration of new type of user fields. This method returns true or an error with description.|[`Bitrix24\SDK\Services\Placement\Service\UserFieldType::add`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Placement/Service/UserFieldType.php#L45-L58)
Return type
[`Bitrix24\SDK\Services\Placement\Result\RegisterUserTypeResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Placement/Result/RegisterUserTypeResult.php)| +|`placement`|[userfieldtype.list](https://training.bitrix24.com/rest_help/application_embedding/user_field/userfieldtype_list.php)|Retrieves list of user field types, registrered by the application. List method. Results in the list of field types with page-by-page navigation.|[`Bitrix24\SDK\Services\Placement\Service\UserFieldType::list`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Placement/Service/UserFieldType.php#L72-L77)
Return type
[`Bitrix24\SDK\Services\Placement\Result\UserFieldTypesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Placement/Result/UserFieldTypesResult.php)| +|`placement`|[userfieldtype.update](https://training.bitrix24.com/rest_help/application_embedding/user_field/userfieldtype_update.php)|Modifies settings of user field types, registered by the application. This method returns true or an error with description.|[`Bitrix24\SDK\Services\Placement\Service\UserFieldType::update`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Placement/Service/UserFieldType.php#L96-L109)
Return type
[`Bitrix24\SDK\Services\Placement\Result\RegisterUserTypeResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Placement/Result/RegisterUserTypeResult.php)| +|`placement`|[userfieldtype.delete](https://training.bitrix24.com/rest_help/application_embedding/user_field/userfieldtype_delete.php)|Deletes user field type, registered by the application. This method returns true or an error with description.|[`Bitrix24\SDK\Services\Placement\Service\UserFieldType::delete`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Placement/Service/UserFieldType.php#L125-L135)
Return type
[`Bitrix24\SDK\Services\Placement\Result\DeleteUserTypeResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Placement/Result/DeleteUserTypeResult.php)| +|`placement`|[placement.bind](https://training.bitrix24.com/rest_help/application_embedding/metods/placement_bind.php)|Installs the embedding location handler|[`Bitrix24\SDK\Services\Placement\Service\Placement::bind`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Placement/Service/Placement.php#L42-L54)
Return type
[`Bitrix24\SDK\Services\Placement\Result\PlacementBindResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Placement/Result/PlacementBindResult.php)| +|`placement`|[placement.unbind](https://training.bitrix24.com/rest_help/application_embedding/metods/placement_unbind.php)|Deletes the registered embedding location handler. Shall be executed with the available account administrative privileges.|[`Bitrix24\SDK\Services\Placement\Service\Placement::unbind`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Placement/Service/Placement.php#L68-L79)
Return type
[`Bitrix24\SDK\Services\Placement\Result\PlacementUnbindResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Placement/Result/PlacementUnbindResult.php)| +|`placement`|[placement.list](https://training.bitrix24.com/rest_help/application_embedding/metods/placement_list.php)|This method is used to retrieve the list of embedding locations, available to the application.|[`Bitrix24\SDK\Services\Placement\Service\Placement::list`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Placement/Service/Placement.php#L93-L100)
Return type
[`Bitrix24\SDK\Services\Placement\Result\PlacementLocationCodesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Placement/Result/PlacementLocationCodesResult.php)| +|`placement`|[placement.get](https://training.bitrix24.com/rest_help/application_embedding/metods/placement_get.php)|This method is used to retrieve the list of registered handlers for embedding locations.|[`Bitrix24\SDK\Services\Placement\Service\Placement::get`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Placement/Service/Placement.php#L114-L117)
Return type
[`Bitrix24\SDK\Services\Placement\Result\PlacementsLocationInformationResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/2.x/src/Services/Placement/Result/PlacementsLocationInformationResult.php)| \ No newline at end of file diff --git a/docs/EN/documentation.md b/docs/EN/documentation.md new file mode 100644 index 00000000..1cea59bd --- /dev/null +++ b/docs/EN/documentation.md @@ -0,0 +1,19 @@ +bitrix24-php-sdk documentation +============================================= + +## Authorisation +- use [incoming webhooks](Core/Auth/auth.md). +- use OAuth2.0 for applications. + +## List of all supported methods +[All methods list](Services/bitrix24-php-sdk-methods.md), this list build automatically. + +## Application development +If you build application based on bitrix24-php-sdk You can use some domain contracts for interoperability. +They store in folder `src/Application/Contracts`. + +Available contracts +- [Bitrix24Accounts](/src/Application/Contracts/Bitrix24Accounts/Docs/Bitrix24Accounts.md) – store auth tokens and provides methods for work with Bitrix24 account. +- [ApplicationInstallations](/src/Application/Contracts/ApplicationInstallations/Docs/ApplicationInstallations.md) – Store information about application installation, linked with Bitrix24 Account with auth tokens. +- [ContactPersons](/src/Application/Contracts/ContactPersons/Docs/ContactPersons.md) – Store information about person who installed application. +- [Bitrix24Partners](/src/Application/Contracts/Bitrix24Partners/Docs/Bitrix24Partners.md) – Store information about Bitrix24 Partner who supports client portal and install or configure application. \ No newline at end of file diff --git a/examples/local-application/composer.json b/examples/local-application/composer.json new file mode 100644 index 00000000..f8462c44 --- /dev/null +++ b/examples/local-application/composer.json @@ -0,0 +1,20 @@ +{ + "name": "mesilov/bitrix24-php-sdk-webhook-example", + "description": "Example for work with bitrix24-php-sdk via webhook", + "minimum-stability": "stable", + "license": "proprietary", + "authors": [ + { + "name": "Maksim Mesilov", + "email": "mesilov.maxim@gmail.com" + } + ], + "require": { + "mesilov/bitrix24-php-sdk": "dev-feature/390-prepare-publish-2-0", + "monolog/monolog": "^3", + "symfony/dotenv": "^7" + }, + "require-dev": { + "roave/security-advisories": "dev-latest" + } +} \ No newline at end of file diff --git a/examples/local-application/index.php b/examples/local-application/index.php new file mode 100644 index 00000000..a5f7fe27 --- /dev/null +++ b/examples/local-application/index.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +use Bitrix24\SDK\Core\Credentials\AuthToken; +use Bitrix24\SDK\Core\Credentials\ApplicationProfile; +use Bitrix24\SDK\Services\ServiceBuilderFactory; +use Monolog\Handler\StreamHandler; +use Monolog\Logger; +use Monolog\Processor\MemoryUsageProcessor; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\HttpFoundation\Request; + +require_once 'vendor/autoload.php'; +?> +
+    Application is worked, auth tokens from bitrix24:
+    
+
+pushHandler(new StreamHandler('bitrix24-php-sdk.log')); +$log->pushProcessor(new MemoryUsageProcessor(true, true)); + +$b24ServiceBuilderFactory = new ServiceBuilderFactory(new EventDispatcher(), $log); +$appProfile = ApplicationProfile::initFromArray([ + 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID' => 'INSERT_HERE_YOUR_DATA', + 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET' => 'INSERT_HERE_YOUR_DATA', + 'BITRIX24_PHP_SDK_APPLICATION_SCOPE' => 'INSERT_HERE_YOUR_DATA' +]); +$b24Service = $b24ServiceBuilderFactory->initFromRequest($appProfile, AuthToken::initFromPlacementRequest($request), $request->get('DOMAIN')); + +var_dump($b24Service->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()); +// get deals list and address to first element +var_dump($b24Service->getCRMScope()->lead()->list([], [], ['ID', 'TITLE'])->getLeads()[0]->TITLE); \ No newline at end of file diff --git a/examples/local-application/install.php b/examples/local-application/install.php new file mode 100644 index 00000000..93388018 --- /dev/null +++ b/examples/local-application/install.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); +?> +
+    Application installation started, tokens from Bitrix24:
+    
+
+ + \ No newline at end of file diff --git a/examples/webhook/composer.json b/examples/webhook/composer.json new file mode 100644 index 00000000..f8462c44 --- /dev/null +++ b/examples/webhook/composer.json @@ -0,0 +1,20 @@ +{ + "name": "mesilov/bitrix24-php-sdk-webhook-example", + "description": "Example for work with bitrix24-php-sdk via webhook", + "minimum-stability": "stable", + "license": "proprietary", + "authors": [ + { + "name": "Maksim Mesilov", + "email": "mesilov.maxim@gmail.com" + } + ], + "require": { + "mesilov/bitrix24-php-sdk": "dev-feature/390-prepare-publish-2-0", + "monolog/monolog": "^3", + "symfony/dotenv": "^7" + }, + "require-dev": { + "roave/security-advisories": "dev-latest" + } +} \ No newline at end of file diff --git a/examples/webhook/example.php b/examples/webhook/example.php new file mode 100644 index 00000000..446fb703 --- /dev/null +++ b/examples/webhook/example.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +use Bitrix24\SDK\Services\ServiceBuilderFactory; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Monolog\Logger; +use Monolog\Handler\StreamHandler; +use Monolog\Processor\MemoryUsageProcessor; + +require_once 'vendor/autoload.php'; + +$webhookUrl = 'INSERT_HERE_YOUR_WEBHOOK_URL'; + +$log = new Logger('bitrix24-php-sdk'); +$log->pushHandler(new StreamHandler('bitrix24-php-sdk.log')); +$log->pushProcessor(new MemoryUsageProcessor(true, true)); + +// create service builder factory +$b24ServiceFactory = new ServiceBuilderFactory(new EventDispatcher(), $log); +// init bitrix24-php-sdk service from webhook +$b24Service = $b24ServiceFactory->initFromWebhook($webhookUrl); + +// work with interested scope +var_dump($b24Service->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()); +// get deals list and address to first element +var_dump($b24Service->getCRMScope()->lead()->list([], [], ['ID', 'TITLE'])->getLeads()[0]->TITLE); diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 00000000..1da108fb --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,22 @@ +parameters: + level: 5 + paths: + - src/ + - tests/Unit/ + - tests/Integration/Services/Telephony + - tests/Integration/Services/User + - tests/Integration/Services/UserConsent + - tests/Integration/Services/IM + - tests/Integration/Services/Catalog + - tests/Integration/Services/IMOpenLines + - tests/Integration/Services/Main + - tests/Integration/Services/Placement + bootstrapFiles: + - tests/bootstrap.php + parallel: + jobSize: 20 + maximumNumberOfProcesses: 8 + minimumNumberOfJobsPerProcess: 2 + editorUrlTitle: '%%relFile%%:%%line%%' + editorUrl: 'phpstorm://open?file=%%file%%&line=%%line%%' + treatPhpDocTypesAsCertain: false diff --git a/phpunit.xml.dist b/phpunit.xml.dist index e3c57095..9976fd86 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,16 +1,46 @@ - - + + + + - - tests/src/ + + ./tests/Unit + + + ./tests/Integration + + + ./tests/Integration/Core/ + + + ./tests/Integration/Services/Telephony/ + + + ./tests/Integration/Services/IM/ + + + ./tests/Integration/Services/IMOpenLines/ + + + ./tests/Integration/Services/Placement/ + + + ./tests/Integration/Services/User/ + + + ./tests/Integration/Services/UserConsent/ + + + ./tests/Integration/Services/Workflows/ - - - src/ - - + + + ./src + + diff --git a/rector.php b/rector.php new file mode 100644 index 00000000..a7f6568e --- /dev/null +++ b/rector.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +use Rector\Config\RectorConfig; +use Rector\Naming\Rector\Class_\RenamePropertyToMatchTypeRector; +use Rector\PHPUnit\Set\PHPUnitSetList; +use Rector\Set\ValueObject\DowngradeLevelSetList; + +return RectorConfig::configure() + ->withPaths([ + __DIR__ . '/src/Core/', + __DIR__ . '/src/Application/', + __DIR__ . '/src/Services/Telephony', + __DIR__ . '/tests/Integration/Services/Telephony', + __DIR__ . '/src/Services/Catalog', + __DIR__ . '/tests/Integration/Services/Catalog', + __DIR__ . '/src/Services/User', + __DIR__ . '/tests/Integration/Services/User', + __DIR__ . '/src/Services/UserConsent', + __DIR__ . '/tests/Integration/Services/UserConsent', + __DIR__ . '/src/Services/IM', + __DIR__ . '/tests/Integration/Services/IM', + __DIR__ . '/src/Services/IMOpenLines', + __DIR__ . '/tests/Integration/Services/IMOpenLines', + __DIR__ . '/src/Services/Main', + __DIR__ . '/tests/Integration/Services/Main', + __DIR__ . '/src/Services/Placement', + __DIR__ . '/tests/Integration/Services/Placement', + __DIR__ . '/tests/Unit/', + ]) + ->withCache(cacheDirectory: __DIR__ . '.cache/rector') + ->withSets( + [ + DowngradeLevelSetList::DOWN_TO_PHP_82, + PHPUnitSetList::PHPUNIT_100 + ] + ) + ->withImportNames( + importNames: false, + importDocBlockNames: false, + importShortClasses: false, + removeUnusedImports: false, + ) + ->withPhpSets( + php82: true // 8.2 + ) + ->withPreparedSets( + deadCode: true, + codeQuality: true, + codingStyle: true, + typeDeclarations: true, + privatization: true, + naming: true, + instanceOf: true, + earlyReturn: true, + strictBooleans: true + ) + ->withSkip([ + RenamePropertyToMatchTypeRector::class + ]); \ No newline at end of file diff --git a/src/Application/ApplicationStatus.php b/src/Application/ApplicationStatus.php new file mode 100644 index 00000000..d5cdbbaa --- /dev/null +++ b/src/Application/ApplicationStatus.php @@ -0,0 +1,133 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application; + +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Symfony\Component\HttpFoundation\Request; + +class ApplicationStatus +{ + private const STATUS_SHORT_FREE = 'F'; + + private const STATUS_SHORT_DEMO = 'D'; + + private const STATUS_SHORT_TRIAL = 'T'; + + private const STATUS_SHORT_PAID = 'P'; + + private const STATUS_SHORT_LOCAL = 'L'; + + private const STATUS_SHORT_SUBSCRIPTION = 'S'; + + private readonly string $statusCode; + + /** + * @throws InvalidArgumentException + */ + public function __construct(string $statusShortCode) + { + $this->statusCode = match ($statusShortCode) { + self::STATUS_SHORT_FREE => 'free', + self::STATUS_SHORT_DEMO => 'demo', + self::STATUS_SHORT_TRIAL => 'trial', + self::STATUS_SHORT_PAID => 'paid', + self::STATUS_SHORT_LOCAL => 'local', + self::STATUS_SHORT_SUBSCRIPTION => 'subscription', + default => throw new InvalidArgumentException( + sprintf('unknown application status code %s', $statusShortCode) + ), + }; + } + + public static function free(): self + { + return new self(self::STATUS_SHORT_FREE); + } + + public function isFree(): bool + { + return 'free' === $this->statusCode; + } + + public function isDemo(): bool + { + return 'demo' === $this->statusCode; + } + + public static function demo(): self + { + return new self(self::STATUS_SHORT_DEMO); + } + + public function isTrial(): bool + { + return 'trial' === $this->statusCode; + } + + public static function trial(): self + { + return new self(self::STATUS_SHORT_TRIAL); + } + + public function isPaid(): bool + { + return 'paid' === $this->statusCode; + } + + public static function paid(): self + { + return new self(self::STATUS_SHORT_PAID); + } + + public function isLocal(): bool + { + return 'local' === $this->statusCode; + } + + public static function local(): self + { + return new self(self::STATUS_SHORT_LOCAL); + } + + public function isSubscription(): bool + { + return 'subscription' === $this->statusCode; + } + + public static function subscription(): self + { + return new self(self::STATUS_SHORT_SUBSCRIPTION); + } + + public function getStatusCode(): string + { + return $this->statusCode; + } + + /** + * @throws InvalidArgumentException + */ + public static function initFromRequest(Request $request): self + { + return new self($request->request->getAlpha('status')); + } + + /** + * @throws InvalidArgumentException + */ + public static function initFromString(string $shortStatusCode): self + { + return new self($shortStatusCode); + } +} \ No newline at end of file diff --git a/src/Application/Contracts/ApplicationInstallations/Docs/ApplicationInstallations.md b/src/Application/Contracts/ApplicationInstallations/Docs/ApplicationInstallations.md new file mode 100644 index 00000000..625935e9 --- /dev/null +++ b/src/Application/Contracts/ApplicationInstallations/Docs/ApplicationInstallations.md @@ -0,0 +1,134 @@ +# Application installation entity + +Store information about application installation, linked with Bitrix24 Account with auth tokens. +Optional can store links to: + +- Client contact person: client person who responsible for application usage +- Bitrix24 Partner contact person: partner contact person who supports client and configure application +- Bitrix24 Partner: partner who supports client portal + +| Method | Return Type | Description | Throws | +|----------------------------------------|---------------------------------|----------------------------------------------------------------------------------------|----------------------------| +| `getId()` | `Uuid` | Returns unique application installation id | | +| `getCreatedAt()` | `CarbonImmutable` | Returns date and time application installation was created | | +| `getUpdatedAt()` | `CarbonImmutable` | Returns date and time of last application installation change | | +| `getBitrix24AccountId()` | `Uuid` | Returns Bitrix24 Account id related to this installation | | +| `getContactPersonId()` | `?Uuid` | Returns contact person id who installed the application on portal (optional) | | +| `changeContactPerson()` | `void` | Changes client contact person | | +| `getBitrix24PartnerContactPersonId()` | `?Uuid` | Returns Bitrix24 partner contact person id (optional) | | +| `changeBitrix24PartnerContactPerson()` | `void` | Changes Bitrix24 partner contact person | | +| `getBitrix24PartnerId()` | `?Uuid` | Returns Bitrix24 Partner id related to this installation (optional) | | +| `changeBitrix24Partner()` | `void` | Changes Bitrix24 partner | | +| `getExternalId()` | `?string` | Returns external id for application installation | | +| `setExternalId()` | `void` | Sets external id for application installation | `InvalidArgumentException` | +| `getStatus()` | `ApplicationInstallationStatus` | Returns application installation status | | +| `applicationInstalled()` | `void` | Finishes application installation | `InvalidArgumentException` | +| `applicationUninstalled()` | `void` | Marks application as uninstalled | `InvalidArgumentException` | +| `markAsActive()` | `void` | Changes status to active for blocked application installation accounts | `InvalidArgumentException` | +| `markAsBlocked()` | `void` | Changes status to blocked for application installation accounts in state new or active | `InvalidArgumentException` | +| `getApplicationStatus()` | `ApplicationStatus` | Returns current application status stored in persistence storage | | +| `changeApplicationStatus()` | `void` | Changes application status | | +| `getPortalLicenseFamily()` | `PortalLicenseFamily` | Returns current Bitrix24 tariff plan designation without specified region | | +| `changePortalLicenseFamily()` | `void` | Changes plan designation without specified region | | +| `getPortalUsersCount()` | `?int` | Returns Bitrix24 portal users count stored in persistence storage | | +| `changePortalUsersCount()` | `void` | Changes Bitrix24 portal users count | | +| `getComment()` | `?string` | Returns comment | | + +## Application installation state diagram + +```mermaid +stateDiagram-v2 + [*] --> New: New installation started + New --> Active : Installation completed successfully + New --> Blocked : Installation aborted + Active --> Blocked : Connection lost or\nforcibly deactivated + Active --> Deleted : Application\n uninstalled + Blocked --> Active : Reconnected or\nreactivated + Blocked --> Deleted : Delete blocked installation + Deleted --> [*]: Installation can be removed\n from persistence storage +``` + +## Repository methods + +- `public function save(ApplicationInstallationInterface $applicationInstallation): void;` + - use case InstallStart + - use case InstallFinish + - use case Uninstall + - use case Activate + - use case Block + - use case ChangeContactPerson + - use case ChangeBitrix24PartnerContactPerson + - use case ChangeBitrix24Partner + - use case LinkToExternalEntity + - use case ChangeApplicationStatus + - use case ChangePortalLicenseFamily + - use case ChangePortalUsersCount +- `public function getById(Uuid $uuid): ApplicationInstallationInterface;` + - use case Activate + - use case Block + - use case InstallFinish + - use case Uninstall + - use case ChangeContactPerson + - use case ChangeBitrix24PartnerContactPerson + - use case ChangeBitrix24Partner + - use case LinkToExternalEntity + - use case ChangeApplicationStatus + - use case ChangePortalLicenseFamily + - use case ChangePortalUsersCount +- `public function delete(Uuid $uuid): void;` + - use case Uninstall +- `public function findByBitrix24AccountId(Uuid $uuid): array;` + - use case InstallFinish + - use case Uninstall + - use case ChangeApplicationStatus + - use case ChangePortalLicenseFamily + - use case ChangePortalUsersCount +- `public function findByExternalId(string $externalId): array;` + - use case LinkToExternalEntity + +## Events + +- `ApplicationInstallationCreatedEvent` – Event triggered when a new installation flow was started +- `ApplicationInstallationFinishedEvent` – Event triggered when application installation flow is finished +- `ApplicationInstallationBlockedEvent` — Event triggered when application installation entity mark as blocked for + administration or technical reasons e.g. application installation was failed +- `ApplicationInstallationApplicationStatusChangedEvent` — Event triggered when background task check actual application + status +- `ApplicationInstallationContactPersonChangedEvent` — Event triggered when user in UI or admin changed client contact + person who responsible for the application +- `ApplicationInstallationBitrix24PartnerContactPersonChangedEvent` — Event triggered when user in UI or admin changed + bitrix24 partner contact person who responsible for application support +- `ApplicationInstallationBitrix24PartnerChangedEvent` — Event triggered when user in UI or admin changed bitrix24 + partner who responsible for application support +- `ApplicationInstallationExternalIdChangedEvent` – Event triggered when application installation linked with external + entity in other system +- `ApplicationInstallationPortalLicenseFamilyChangedEvent` – Event triggered when background task check actual + PortalLicenseFamily +- `ApplicationInstallationPortalUsersCountChangedEvent` – Event triggered when background task check actual users count +- `ApplicationInstallationUnblockedEvent` – Event triggered when application installation entity mark as active +- `ApplicationInstallationUninstalledEvent` — Event triggered when application uninstalled from portal + +```mermaid +%%{init: { 'logLevel': 'debug', 'theme': 'neutral' } }%% +timeline + title Application Installation timeline + section Application installation period + Create new Application Installation entity when install start : «Application Installation Created Event» + Activate Application Installation entity if install finish : «Application Installation Finished Event» + Block Application Installation entity if install failure : «Application Installation Blocked Event» + section Application active period + Change application status : «Application Installation Application Status Changed Event» + Change client contact person who responsible for application : «Application Installation Contact Person Changed Event» + Change Bitrix24 partner contact who responsible for support application : «Application Installation Bitrix24 Partner Contact Person Changed Event» + Change Bitrix24 partner whor responsible for portal support : «Application Installation Bitrix24 Partner Changed Event» + Link application installation to another entity in external system : «Application Installation ExternalId Changed Event» + Request Bitrix24 portal license type : «Application Installation Portal License Family Changed Event» + Calculate Bitrix24 portal users count: «Application Installation Portal Users Count Changed Event» + Unblock Application Installation entity : «Application Installation Unblocked Event» + section Application uninstall period + Administrator Uninstalled Application : «Application Installation Uninstalled Event» +``` +## Background periodical tasks +- check portal license type +- check application status +- check users count \ No newline at end of file diff --git a/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterface.php b/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterface.php new file mode 100644 index 00000000..2113d6da --- /dev/null +++ b/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterface.php @@ -0,0 +1,208 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Entity; + +use Bitrix24\SDK\Application\ApplicationStatus; +use Bitrix24\SDK\Application\PortalLicenseFamily; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; + +interface ApplicationInstallationInterface +{ + /** + * @return Uuid unique application installation id + */ + public function getId(): Uuid; + + /** + * @return CarbonImmutable date and time application installation create + */ + public function getCreatedAt(): CarbonImmutable; + + /** + * @return CarbonImmutable date and time application installation last change + */ + public function getUpdatedAt(): CarbonImmutable; + + /** + * Get Bitrix24 Account id related with this installation + * + * Return bitrix24 account with tokens related with user who installed application on portal + * + * @return Uuid bitrix24 account id + */ + public function getBitrix24AccountId(): Uuid; + + /** + * Get Contact Person id + * + * Return contact person id who install application on portal, optional + * + * @return Uuid|null get contact person id + */ + public function getContactPersonId(): ?Uuid; + + /** + * Change contact person + * + * Change client contact person if client say he has new responsible for the application + */ + public function changeContactPerson(?Uuid $uuid): void; + + /** + * Get Bitrix24 Partner contact person id, optional + * + * Return bitrix24 partner contact person id - if application supported wih another partner + */ + public function getBitrix24PartnerContactPersonId(): ?Uuid; + + /** + * Change bitrix24 partner contact person + * + * Change bitrix24 partner contact person if partner say he has new responsible for the application + */ + public function changeBitrix24PartnerContactPerson(?Uuid $uuid): void; + + /** + * @return Uuid|null get Bitrix24 Partner id related with this installation, optional + */ + public function getBitrix24PartnerId(): ?Uuid; + + /** + * Change bitrix24 partner + * + * Change bitrix24 partner if other partner starts support client portal + */ + public function changeBitrix24Partner(?Uuid $uuid): void; + + /** + * Get external id for application installation + * + * Return external id for application installation related entity in crm or erp - lead or deal id + */ + public function getExternalId(): ?string; + + /** + * Get external id for application installation + * + * Set external id for application installation related entity in crm or erp - lead or deal id + * @param non-empty-string|null $externalId + * @throws InvalidArgumentException + */ + public function setExternalId(?string $externalId): void; + + /** + * Get application installation status + * + * new - started the installation procedure, but have not yet finalized, there is no “installation completed” + * active - installation finished, active portal, there is a connection to B24 + * deleted - application has been removed from the portal + * blocked - lost connection with the portal or the developer forcibly deactivated the account + */ + public function getStatus(): ApplicationInstallationStatus; + + /** + * Finish application installation + * + * Installation can be finished only for state «new» + * @throws InvalidArgumentException + */ + public function applicationInstalled(): void; + + /** + * Application uninstalled + * + * Application can be uninstalled by: + * - admin on portal active → deleted statuses + * - if installation will not complete new → blocked → deleted by background task + * @throws InvalidArgumentException + */ + public function applicationUninstalled(): void; + + /** + * Change status to active for blocked application installation accounts + * + * You can activate accounts only blocked state + * + * @param non-empty-string|null $comment + * @throws InvalidArgumentException + */ + public function markAsActive(?string $comment): void; + + /** + * Change status to blocked for application installation accounts in state new or active + * + * You can block installation account if you need temporally stop installation work + * + * @param non-empty-string|null $comment + * @throws InvalidArgumentException + */ + public function markAsBlocked(?string $comment): void; + + /** + * Get application status + * + * Return current application status stored in persistence storage. + * This method do not call bitrix24 rest api to get actual data + * @link https://training.bitrix24.com/rest_help/general/app_info.php + */ + public function getApplicationStatus(): ApplicationStatus; + + /** + * Change application status + * + * You can check application status in periodical background task and store it in persistence storage for BI analytics + * @link https://training.bitrix24.com/rest_help/general/app_info.php + */ + public function changeApplicationStatus(ApplicationStatus $applicationStatus): void; + + /** + * Get bitrix24 tariff plan designation without specified region. + * + * Return current bitrix24 tariff plan designation without specified region stored in persistence storage. + * This method do not call bitrix24 rest api to get actual data + * @link https://training.bitrix24.com/rest_help/general/app_info.php + */ + public function getPortalLicenseFamily(): PortalLicenseFamily; + + /** + * Change plan designation without specified region. + * + * You can check portal license family in periodical background task and store it in persistence storage for BI analytics + * @link https://training.bitrix24.com/rest_help/general/app_info.php + */ + public function changePortalLicenseFamily(PortalLicenseFamily $portalLicenseFamily): void; + + /** + * Get bitrix24 portal users count + * + * Return bitrix24 portal users count stored in persistence storage + * This method do not call bitrix24 rest api to get actual data + */ + public function getPortalUsersCount(): ?int; + + /** + * Change bitrix24 portal users count + * + * You can check portal users count background task and store it in persistence storage for BI analytics + */ + public function changePortalUsersCount(int $usersCount): void; + + /** + * Get comment + */ + public function getComment(): ?string; +} diff --git a/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationStatus.php b/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationStatus.php new file mode 100644 index 00000000..985e0927 --- /dev/null +++ b/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationStatus.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Entity; + +enum ApplicationInstallationStatus: string +{ + case new = 'new'; // started the installation procedure, but have not yet finalized, there is no “installation completed” + case active = 'active'; // active portal, there is a connection to B24 + case deleted = 'deleted'; // the app has been removed from the portal + case blocked = 'blocked'; // lost connection with the portal or the developer forcibly deactivated the account +} \ No newline at end of file diff --git a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationApplicationStatusChangedEvent.php b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationApplicationStatusChangedEvent.php new file mode 100644 index 00000000..19f00de5 --- /dev/null +++ b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationApplicationStatusChangedEvent.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Events; + +use Bitrix24\SDK\Application\ApplicationStatus; +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class ApplicationInstallationApplicationStatusChangedEvent extends Event +{ + public function __construct( + public readonly Uuid $applicationInstallationId, + public readonly CarbonImmutable $timestamp, + public readonly ApplicationStatus $applicationStatus) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationBitrix24PartnerChangedEvent.php b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationBitrix24PartnerChangedEvent.php new file mode 100644 index 00000000..1b5fdaa3 --- /dev/null +++ b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationBitrix24PartnerChangedEvent.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class ApplicationInstallationBitrix24PartnerChangedEvent extends Event +{ + public function __construct( + public readonly Uuid $applicationInstallationId, + public readonly CarbonImmutable $timestamp, + public readonly ?Uuid $previousBitrix24PartnerId, + public readonly ?Uuid $currentBitrix24PartnerId) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationBitrix24PartnerContactPersonChangedEvent.php b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationBitrix24PartnerContactPersonChangedEvent.php new file mode 100644 index 00000000..1569a932 --- /dev/null +++ b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationBitrix24PartnerContactPersonChangedEvent.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class ApplicationInstallationBitrix24PartnerContactPersonChangedEvent extends Event +{ + public function __construct( + public readonly Uuid $applicationInstallationId, + public readonly CarbonImmutable $timestamp, + public readonly ?Uuid $previousBitrix24PartnerContactPersonId, + public readonly ?Uuid $currentBitrix24PartnerContactPersonId) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationBlockedEvent.php b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationBlockedEvent.php new file mode 100644 index 00000000..c0df86e9 --- /dev/null +++ b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationBlockedEvent.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class ApplicationInstallationBlockedEvent extends Event +{ + public function __construct( + public readonly Uuid $applicationInstallationId, + public readonly CarbonImmutable $timestamp, + public readonly ?string $comment) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationContactPersonChangedEvent.php b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationContactPersonChangedEvent.php new file mode 100644 index 00000000..1b3b7861 --- /dev/null +++ b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationContactPersonChangedEvent.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class ApplicationInstallationContactPersonChangedEvent extends Event +{ + public function __construct( + public readonly Uuid $applicationInstallationId, + public readonly CarbonImmutable $timestamp, + public readonly ?Uuid $previousContactPersonId, + public readonly ?Uuid $currentContactPersonId) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationCreatedEvent.php b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationCreatedEvent.php new file mode 100644 index 00000000..b3498a2c --- /dev/null +++ b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationCreatedEvent.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class ApplicationInstallationCreatedEvent extends Event +{ + public function __construct( + public readonly Uuid $applicationInstallationId, + public readonly CarbonImmutable $timestamp, + public readonly Uuid $bitrix24AccountId) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationExternalIdChangedEvent.php b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationExternalIdChangedEvent.php new file mode 100644 index 00000000..68faf3c5 --- /dev/null +++ b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationExternalIdChangedEvent.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class ApplicationInstallationExternalIdChangedEvent extends Event +{ + public function __construct( + public readonly Uuid $applicationInstallationId, + public readonly CarbonImmutable $timestamp, + public readonly ?string $previousExternalId, + public readonly ?string $currentExternalId) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationFinishedEvent.php b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationFinishedEvent.php new file mode 100644 index 00000000..191d99be --- /dev/null +++ b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationFinishedEvent.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Events; + +use Bitrix24\SDK\Application\PortalLicenseFamily; +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class ApplicationInstallationFinishedEvent extends Event +{ + public function __construct( + public readonly Uuid $applicationInstallationId, + public readonly CarbonImmutable $timestamp, + public readonly Uuid $bitrix24AccountId, + public readonly PortalLicenseFamily $portalLicenseFamily, + public readonly ?Uuid $contactPersonId, + public readonly ?Uuid $bitrix24PartnerContactPersonId, + public readonly ?Uuid $bitrix24PartnerId) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationPortalLicenseFamilyChangedEvent.php b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationPortalLicenseFamilyChangedEvent.php new file mode 100644 index 00000000..18931dd3 --- /dev/null +++ b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationPortalLicenseFamilyChangedEvent.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Events; + +use Bitrix24\SDK\Application\PortalLicenseFamily; +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class ApplicationInstallationPortalLicenseFamilyChangedEvent extends Event +{ + public function __construct( + public readonly Uuid $applicationInstallationId, + public readonly CarbonImmutable $timestamp, + public readonly PortalLicenseFamily $previousPortalLicenseFamily, + public readonly PortalLicenseFamily $currentPortalLicenseFamily) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationPortalUsersCountChangedEvent.php b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationPortalUsersCountChangedEvent.php new file mode 100644 index 00000000..bdb6695e --- /dev/null +++ b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationPortalUsersCountChangedEvent.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class ApplicationInstallationPortalUsersCountChangedEvent extends Event +{ + public function __construct( + public readonly Uuid $applicationInstallationId, + public readonly CarbonImmutable $timestamp, + public readonly ?int $previousPortalUserCount, + public readonly ?int $currentPortalUserCount) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationUnblockedEvent.php b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationUnblockedEvent.php new file mode 100644 index 00000000..91788c03 --- /dev/null +++ b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationUnblockedEvent.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class ApplicationInstallationUnblockedEvent extends Event +{ + public function __construct( + public readonly Uuid $applicationInstallationId, + public readonly CarbonImmutable $timestamp, + public readonly ?string $comment) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationUninstalledEvent.php b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationUninstalledEvent.php new file mode 100644 index 00000000..06256df8 --- /dev/null +++ b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationUninstalledEvent.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class ApplicationInstallationUninstalledEvent extends Event +{ + public function __construct( + public readonly Uuid $applicationInstallationId, + public readonly CarbonImmutable $timestamp, + public readonly Uuid $bitrix24AccountId, + public readonly ?Uuid $contactPersonId, + public readonly ?Uuid $bitrix24PartnerContactPersonId, + public readonly ?Uuid $bitrix24PartnerId, + public readonly ?string $externalId) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/ApplicationInstallations/Exceptions/ApplicationInstallationNotFoundException.php b/src/Application/Contracts/ApplicationInstallations/Exceptions/ApplicationInstallationNotFoundException.php new file mode 100644 index 00000000..a25bce8e --- /dev/null +++ b/src/Application/Contracts/ApplicationInstallations/Exceptions/ApplicationInstallationNotFoundException.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Exceptions; + +use Bitrix24\SDK\Core\Exceptions\BaseException; + +class ApplicationInstallationNotFoundException extends BaseException +{ +} \ No newline at end of file diff --git a/src/Application/Contracts/ApplicationInstallations/Repository/ApplicationInstallationRepositoryInterface.php b/src/Application/Contracts/ApplicationInstallations/Repository/ApplicationInstallationRepositoryInterface.php new file mode 100644 index 00000000..51e9c786 --- /dev/null +++ b/src/Application/Contracts/ApplicationInstallations/Repository/ApplicationInstallationRepositoryInterface.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Repository; + +use Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Entity\ApplicationInstallationInterface; +use Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Exceptions\ApplicationInstallationNotFoundException; +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Symfony\Component\Uid\Uuid; + +interface ApplicationInstallationRepositoryInterface +{ + /** + * Save application installation fact to persistence storage + */ + public function save(ApplicationInstallationInterface $applicationInstallation): void; + + /** + * Get application installation by id + * + * + * @throws ApplicationInstallationNotFoundException + */ + public function getById(Uuid $uuid): ApplicationInstallationInterface; + + /** + * Delete application installation from persistence storage + * + * @throws ApplicationInstallationNotFoundException + * @throws InvalidArgumentException + */ + public function delete(Uuid $uuid): void; + + /** + * Find application installation by bitrix24 account id + * + * @return ApplicationInstallationInterface[] + */ + public function findByBitrix24AccountId(Uuid $uuid): array; + + /** + * Find application installation by external id + * + * @param non-empty-string $externalId + * @return ApplicationInstallationInterface[] + * @throws InvalidArgumentException + */ + public function findByExternalId(string $externalId): array; +} \ No newline at end of file diff --git a/src/Application/Contracts/Bitrix24Accounts/Docs/Bitrix24Accounts.md b/src/Application/Contracts/Bitrix24Accounts/Docs/Bitrix24Accounts.md new file mode 100644 index 00000000..226baef4 --- /dev/null +++ b/src/Application/Contracts/Bitrix24Accounts/Docs/Bitrix24Accounts.md @@ -0,0 +1,94 @@ +# Bitrix24 account entity + +Store auth tokens and provides methods for work with Bitrix24 account. + +| Method | Return Type | Description | Throws | +|------------------------------|-------------------------|-------------------------------------------------------------|--------------------------| +| `getId()` | `Uuid` | Returns the unique account ID. | - | +| `getBitrix24UserId()` | `int` | Returns the Bitrix24 user ID who installed the application. | - | +| `isBitrix24UserAdmin()` | `bool` | Checks if the Bitrix24 user has admin rights. | - | +| `getMemberId()` | `string` | Returns the unique portal ID. | - | +| `getDomainUrl()` | `string` | Returns the portal domain URL. | - | +| `getStatus()` | `Bitrix24AccountStatus` | Returns the account status. | - | +| `getAuthToken()` | `AuthToken` | Returns the authentication token. | - | +| `renewAuthToken()` | `void` | Renews the authentication token. | - | +| `getApplicationVersion()` | `int` | Returns the application version. | - | +| `getApplicationScope()` | `Scope` | Returns the application scope (permissions). | - | +| `changeDomainUrl()` | `void` | Changes the domain URL after a portal rename. | - | +| `applicationInstalled()` | `void` | Sets the account status to "active". | InvalidArgumentException | +| `applicationUninstalled()` | `void` | Sets the account status to "deleted". | InvalidArgumentException | +| `isApplicationTokenValid()` | `bool` | Checks if the provided application token is valid. | - | +| `getCreatedAt()` | `CarbonImmutable` | Returns the account creation date and time. | - | +| `getUpdatedAt()` | `CarbonImmutable` | Returns the last account update date and time. | - | +| `updateApplicationVersion()` | `void` | Updates the application version. | InvalidArgumentException | +| `markAsActive()` | `void` | Changes the account status to active. | InvalidArgumentException | +| `markAsBlocked()` | `void` | Changes the account status to blocked. | InvalidArgumentException | +| `getComment()` | `?string` | Returns the comment for this account. | - | + +## Bitrix24 account state diagram + +```mermaid +stateDiagram-v2 + [*] --> New: New account when\ninstallation started + New --> Active : Installation completed successfully + New --> Blocked : Installation aborted + Active --> Blocked : Connection lost or\nforcibly deactivated + Active --> Deleted : Application\n uninstalled + Blocked --> Active : Reconnected or\nreactivated + Blocked --> Deleted : Delete blocked account + Deleted --> [*]: Account can be removed\n from persistence storage +``` + +## Repository methods + +- `save(Bitrix24AccountInterface $bitrix24Account): void` + - use case Activate + - use case Block + - use case ChangeDomainUrl + - use case InstallStart + - use case InstallFinish + - use case RenewAuthToken + - use case Uninstall + - use case UpdateVersion +- `getById(Uuid $uuid): Bitrix24AccountInterface` + - use case Activate + - use case Block +- `delete(Uuid $uuid)` + - use case Uninstall +- `findByMemberId(string $memberId, ?Bitrix24AccountStatus $status = null, ?bool $isAdmin = null): array` + - use case InstallStart + - use case InstallFinish + - use case RenewAuthToken + - use case Uninstall + - use case UpdateVersion (what about multiple accounts???) +- `findByDomain(string $domainUrl, ?Bitrix24AccountStatus $status = null, ?bool $isAdmin = null): array` + - use case ChangeDomainUrl +- `findOneAdminByMemberId(string $memberId): ?Bitrix24AccountInterface` + +## Events +```mermaid +%%{init: { 'logLevel': 'debug', 'theme': 'neutral' } }%% +timeline + title Bitrix24 account timeline + section Application installation period + Create new account when install start : Bitrix24 Account Created Event + Activate account if install finish : Bitrix24 Account Application Installed Event + Block Account if install failure : Bitrix24 Account Blocked Event + section Application active period + Change domain URL if portal renamed : Bitrix24 Account DomainUrl Changed Event + Block Account : Bitrix24 Account Blocked Event + Unblock Account : Bitrix24 Account Unblocked Event + Update Application Version : Bitrix24 Account Application Version Updated Event + section Application uninstall period + Administrator Uninstalled Application : Bitrix24 Account Application Uninstalled Event + Delete account : Bitrix24 Account Deleted Event +``` + +- `Bitrix24AccountCreatedEvent` — event is triggered when a new Bitrix24 account is created. The account is initially in a `New` state, and the installation process has begun. +- `Bitrix24AccountApplicationInstalledEvent` — event is triggered when an application is successfully installed. It signifies that account finish installation flow. +- `Bitrix24AccountDomainUrlChangedEvent` — event is triggered when the domain URL associated with a Bitrix24 account is modified. +- `Bitrix24AccountBlockedEvent` — event occurs when a Bitrix24 account is blocked. This could be due to various reasons such as lost auth token, policy violations, or at the request of the account owner. +- `Bitrix24AccountUnblockedEvent` — event is triggered when a previously blocked Bitrix24 account is unblocked and restored to normal functioning. +- `Bitrix24AccountApplicationVersionUpdatedEvent` — event is triggered when an installed application within a Bitrix24 account is updated to a newer version. It signifies that the application has been successfully upgraded with new features or fixes. +- `Bitrix24AccountApplicationUninstalledEvent` — event is triggered when an application uninstalled from a Bitrix24 account. +- `Bitrix24AccountDeletedEvent` — event is triggered when a Bitrix24 account is permanently deleted. This likely represents the final stage in an account's lifecycle and might involve data removal and cleanup processes. diff --git a/src/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterface.php b/src/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterface.php new file mode 100644 index 00000000..9a978e79 --- /dev/null +++ b/src/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterface.php @@ -0,0 +1,135 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity; + +use Bitrix24\SDK\Core\Credentials\AuthToken; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Response\DTO\RenewedAuthToken; +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; + +interface Bitrix24AccountInterface +{ + /** + * @return Uuid unique account id + */ + public function getId(): Uuid; + + /** + * @return positive-int Bitrix24 user id who installed application and own this account + */ + public function getBitrix24UserId(): int; + + /** + * @return bool Is bitrix24 user has admin rights on portal + */ + public function isBitrix24UserAdmin(): bool; + + /** + * @return non-empty-string unique portal id + */ + public function getMemberId(): string; + + /** + * @return non-empty-string portal domain url + */ + public function getDomainUrl(): string; + + /** + * @return Bitrix24AccountStatus account status + */ + public function getStatus(): Bitrix24AccountStatus; + + /** + * @return AuthToken get auth token with access and refresh tokens + */ + public function getAuthToken(): AuthToken; + + + public function renewAuthToken(RenewedAuthToken $renewedAuthToken): void; + + /** + * @return int application version + */ + public function getApplicationVersion(): int; + + /** + * @return Scope Get application scope (permissions) + */ + public function getApplicationScope(): Scope; + + /** + * @param non-empty-string $newDomainUrl new domain url after portal rename b24-hnst2u.bitrix24.com → acme-inc.bitrix24.com + */ + public function changeDomainUrl(string $newDomainUrl): void; + + /** + * @param non-empty-string $applicationToken Application installed on portal and finish installation flow, set status «active» + * @throws InvalidArgumentException + */ + public function applicationInstalled(string $applicationToken): void; + + /** + * @param string $applicationToken Application uninstalled from portal, set status «deleted» + * @throws InvalidArgumentException + */ + public function applicationUninstalled(string $applicationToken): void; + + /** + * Check is application token valid + * + * @param non-empty-string $applicationToken + * @link https://training.bitrix24.com/rest_help/general/events/event_safe.php + */ + public function isApplicationTokenValid(string $applicationToken): bool; + + /** + * @return CarbonImmutable date and time account create + */ + public function getCreatedAt(): CarbonImmutable; + + /** + * @return CarbonImmutable date and time account last change + */ + public function getUpdatedAt(): CarbonImmutable; + + /** + * Update application version if application was updated in marketplace + * + * @param positive-int $version application version from marketplace + * @param Scope|null $newScope new scope if scope was changed + * @throws InvalidArgumentException + */ + public function updateApplicationVersion(int $version, ?Scope $newScope): void; + + /** + * Change account status to active + * @param non-empty-string|null $comment + * @throws InvalidArgumentException + */ + public function markAsActive(?string $comment): void; + + /** + * Change account status to blocked + * @param non-empty-string|null $comment + * @throws InvalidArgumentException + */ + public function markAsBlocked(?string $comment): void; + + /** + * @return non-empty-string|null get comment for this account + */ + public function getComment(): ?string; +} diff --git a/src/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountStatus.php b/src/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountStatus.php new file mode 100644 index 00000000..52c871d1 --- /dev/null +++ b/src/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountStatus.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity; + +enum Bitrix24AccountStatus: string +{ + case new = 'new'; // started the installation procedure, but have not yet finalized, there is no “installation completed” + case active = 'active'; // active portal, there is a connection to B24 + case deleted = 'deleted'; // the app has been removed from the portal + case blocked = 'blocked'; // lost connection with the portal or the developer forcibly deactivated the account +} \ No newline at end of file diff --git a/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountApplicationInstalledEvent.php b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountApplicationInstalledEvent.php new file mode 100644 index 00000000..67c03e01 --- /dev/null +++ b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountApplicationInstalledEvent.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class Bitrix24AccountApplicationInstalledEvent extends Event +{ + public function __construct( + public readonly Uuid $bitrix24AccountId, + public readonly CarbonImmutable $timestamp) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountApplicationUninstalledEvent.php b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountApplicationUninstalledEvent.php new file mode 100644 index 00000000..2928b59b --- /dev/null +++ b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountApplicationUninstalledEvent.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class Bitrix24AccountApplicationUninstalledEvent extends Event +{ + public function __construct( + public readonly Uuid $bitrix24AccountId, + public readonly CarbonImmutable $timestamp + ) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountApplicationVersionUpdatedEvent.php b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountApplicationVersionUpdatedEvent.php new file mode 100644 index 00000000..fe98e4a4 --- /dev/null +++ b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountApplicationVersionUpdatedEvent.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class Bitrix24AccountApplicationVersionUpdatedEvent extends Event +{ + public function __construct( + public readonly Uuid $bitrix24AccountId, + public readonly CarbonImmutable $timestamp) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountBlockedEvent.php b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountBlockedEvent.php new file mode 100644 index 00000000..4a397dc6 --- /dev/null +++ b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountBlockedEvent.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class Bitrix24AccountBlockedEvent extends Event +{ + public function __construct( + public readonly Uuid $bitrix24AccountId, + public readonly CarbonImmutable $timestamp) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountCreatedEvent.php b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountCreatedEvent.php new file mode 100644 index 00000000..8458ecce --- /dev/null +++ b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountCreatedEvent.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class Bitrix24AccountCreatedEvent extends Event +{ + public function __construct( + public readonly Uuid $bitrix24AccountId, + public readonly CarbonImmutable $timestamp) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountDeletedEvent.php b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountDeletedEvent.php new file mode 100644 index 00000000..a2ab5139 --- /dev/null +++ b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountDeletedEvent.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class Bitrix24AccountDeletedEvent extends Event +{ + public function __construct( + public readonly Uuid $bitrix24AccountId, + public readonly CarbonImmutable $timestamp) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountDomainUrlChangedEvent.php b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountDomainUrlChangedEvent.php new file mode 100644 index 00000000..2be28c02 --- /dev/null +++ b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountDomainUrlChangedEvent.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class Bitrix24AccountDomainUrlChangedEvent extends Event +{ + public function __construct( + public readonly Uuid $bitrix24AccountId, + public readonly CarbonImmutable $timestamp) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountUnblockedEvent.php b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountUnblockedEvent.php new file mode 100644 index 00000000..3227745e --- /dev/null +++ b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountUnblockedEvent.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class Bitrix24AccountUnblockedEvent extends Event +{ + public function __construct( + public readonly Uuid $bitrix24AccountId, + public readonly CarbonImmutable $timestamp) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/Bitrix24Accounts/Exceptions/Bitrix24AccountNotFoundException.php b/src/Application/Contracts/Bitrix24Accounts/Exceptions/Bitrix24AccountNotFoundException.php new file mode 100644 index 00000000..9ff84446 --- /dev/null +++ b/src/Application/Contracts/Bitrix24Accounts/Exceptions/Bitrix24AccountNotFoundException.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Exceptions; + +use Bitrix24\SDK\Core\Exceptions\BaseException; + +class Bitrix24AccountNotFoundException extends BaseException +{ +} \ No newline at end of file diff --git a/src/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterface.php b/src/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterface.php new file mode 100644 index 00000000..50d48fa8 --- /dev/null +++ b/src/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterface.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Repository; + +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts; +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountInterface; +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountStatus; +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Exceptions\Bitrix24AccountNotFoundException; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Symfony\Component\Uid\Uuid; + +interface Bitrix24AccountRepositoryInterface +{ + /** + * Save bitrix24 account to persistence storage + */ + public function save(Bitrix24AccountInterface $bitrix24Account): void; + + /** + * Delete bitrix24 account from + * @throws Bitrix24AccountNotFoundException + * @throws InvalidArgumentException + */ + public function delete(Uuid $uuid): void; + + /** + * Get bitrix24 account by id + * @throws Bitrix24AccountNotFoundException + */ + public function getById(Uuid $uuid): Bitrix24AccountInterface; + + /** + * Find one admin bitrix24 account by member_id + * @param non-empty-string $memberId + */ + public function findOneAdminByMemberId(string $memberId): ?Bitrix24AccountInterface; + + /** + * Find bitrix24 accounts by member_id and filter by status and isAdmin flag + * @param non-empty-string $memberId + * @return Bitrix24AccountInterface[] + */ + public function findByMemberId(string $memberId, ?Bitrix24AccountStatus $bitrix24AccountStatus = null, ?bool $isAdmin = null): array; + + /** + * Find bitrix24 accounts by domain url and filter by status adn isAdmin flag + * @param non-empty-string $domainUrl + * @return Bitrix24AccountInterface[] + */ + public function findByDomain(string $domainUrl, ?Bitrix24AccountStatus $bitrix24AccountStatus = null, ?bool $isAdmin = null): array; +} \ No newline at end of file diff --git a/src/Application/Contracts/Bitrix24Partners/Docs/Bitrix24Partners.md b/src/Application/Contracts/Bitrix24Partners/Docs/Bitrix24Partners.md new file mode 100644 index 00000000..24d88c9d --- /dev/null +++ b/src/Application/Contracts/Bitrix24Partners/Docs/Bitrix24Partners.md @@ -0,0 +1,108 @@ +# Bitrix24 Partner entity + +Store information about Bitrix24 Partner who supports client portal and install or configure application. + +| Method | Return Type | Description | Throws | +|--------------------------|-------------------------|------------------------------------------------------------------------|----------------------------| +| `getId()` | `Uuid` | Returns Bitrix24 partner id | | +| `getCreatedAt()` | `CarbonImmutable` | Returns date and time Bitrix24 partner was created | | +| `getUpdatedAt()` | `CarbonImmutable` | Returns date and time of last Bitrix24 partner change | | +| `getExternalId()` | `?string` | Returns external id for Bitrix24 partner | | +| `setExternalId()` | `void` | Sets external id for Bitrix24 partner | `InvalidArgumentException` | +| `getStatus()` | `Bitrix24PartnerStatus` | Returns Bitrix24 partner status | | +| `markAsActive()` | `void` | Changes status to active for blocked Bitrix24 partner accounts | `InvalidArgumentException` | +| `markAsBlocked()` | `void` | Changes status to blocked for Bitrix24 partner account in active state | `InvalidArgumentException` | +| `markAsDeleted()` | `void` | Changes status to deleted for Bitrix24 partner account (soft delete) | `InvalidArgumentException` | +| `getComment()` | `?string` | Returns comment | | +| `getTitle()` | `string` | Returns partner title | | +| `setTitle()` | `void` | Sets partner title | `InvalidArgumentException` | +| `getSite()` | `?string` | Returns partner site | | +| `setSite()` | `void` | Sets partner site | `InvalidArgumentException` | +| `getPhone()` | `?PhoneNumber` | Returns partner phone | | +| `setPhone()` | `void` | Sets partner phone | | +| `getEmail()` | `?string` | Returns partner email | | +| `setEmail()` | `void` | Sets partner email | `InvalidArgumentException` | +| `getBitrix24PartnerId()` | `?int` | Returns Bitrix24 partner id | | +| `setBitrix24PartnerId()` | `void` | Sets Bitrix24 partner id | `InvalidArgumentException` | +| `getOpenLineId()` | `?string` | Returns open line id | | +| `setOpenLineId()` | `void` | Sets open line id | `InvalidArgumentException` | + +## Bitrix24 partner state diagram + +```mermaid +stateDiagram-v2 + [*] --> Active: Active Bitrix24 Partner + Active --> Blocked : Partner closed or\nforcibly deactivated + Active --> Deleted : Partner \ndeleted + Blocked --> Active : Partner \nreactivated + Blocked --> Deleted : Delete blocked partner + Deleted --> [*]: Bitrix24 partner can be removed\nfrom persistence storage +``` + +## Repository methods + +- `public function save(Bitrix24PartnerInterface $bitrix24Partner): void;` + - use case Activate + - use case Block + - use case Delete + - use case SetExternalId + - use case SetTitle + - use case SetSite + - use case SetPhone + - use case SetEmail + - use case SetOpenLineId + - use case SetBitrix24PartnerId + - use case Create +- `public function delete(Uuid $uuid): void;` + - use case Delete +- `public function getById(Uuid $uuid): Bitrix24PartnerInterface;` + - use case Activate + - use case Block + - use case Delete + - use case SetExternalId + - use case SetTitle + - use case SetSite + - use case SetPhone + - use case SetEmail + - use case SetBitrix24PartnerId + - use case SetOpenLineId +- `public function findByBitrix24PartnerId(int $bitrix24PartnerId): ?Bitrix24PartnerInterface;` + - use case SetBitrix24PartnerId +- `public function findByTitle(string $title): array;` + - use case Create + - use case SetSite +- `public function findByExternalId(string $externalId, ?Bitrix24PartnerStatus $bitrix24PartnerStatus = null): array;` + - use case SetExternalId + +## Events + +- `Bitrix24PartnerCreatedEvent` – Event triggered when a new Bitrix24 partner was created. +- `Bitrix24PartnerBlockedEvent` – Event triggered when a Bitrix24 partner was blocked for some reason. +- `Bitrix24PartnerUnblockedEvent` – Event triggered when a Bitrix24 partner was unblocked. +- `Bitrix24PartnerEmailChangedEvent` – Event triggered when a Bitrix24 partner email was changed. +- `Bitrix24PartnerExternalIdChangedEvent` – Event triggered when a Bitrix24 partner external id was changed. +- `Bitrix24PartnerOpenLineIdChangedEvent` – Event triggered when a Bitrix24 partner open line id was changed. +- `Bitrix24PartnerPartnerIdChangedEvent` – Event triggered when a Bitrix24 partner id was changed. +- `Bitrix24PartnerPhoneChangedEvent` – Event triggered when a Bitrix24 partner phone was changed. +- `Bitrix24PartnerSiteChangedEvent` – Event triggered when a Bitrix24 partner site was changed. +- `Bitrix24PartnerTitleChangedEvent` – Event triggered when a Bitrix24 partner title was changed. +- `Bitrix24PartnerDeletedEvent` – Event triggered when a Bitrix24 partner deleted. + +```mermaid +%%{init: { 'logLevel': 'debug', 'theme': 'neutral' } }%% +timeline +title Bitrix24 Partner timeline +section Application installation period +Create new Bitrix24 Partner item if can't find by title or Bitrix24 partner id in exists list: «Bitrix24 Partner Created Event» +section Application active period +Block entity for some reason : «Bitrix24 Partner Blocked Event» +Unblock entity for some reason : «Bitrix24 Partner Unblocked Event» +Change contact email : «Bitrix24 Partner Email Changed Event» +Change external id : «Bitrix24 Partner ExternalId Changed Event» +Change open line id : «Bitrix24 Partner Open Line Id Changed Event» +Change Bitrix24 Partner id : «Bitrix24 Partner Partner Id Changed Event» +Change phone : «Bitrix24 Partner Phone Changed Event» +Change website : «Bitrix24 Partner Site Changed Event» +Change partner title : «Bitrix24 Partner Title Changed Event» +Delete entity : «Bitrix24 Partner Deleted Event» +``` \ No newline at end of file diff --git a/src/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterface.php b/src/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterface.php new file mode 100644 index 00000000..21f90883 --- /dev/null +++ b/src/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterface.php @@ -0,0 +1,168 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Entity; + +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Carbon\CarbonImmutable; +use libphonenumber\PhoneNumber; +use Symfony\Component\Uid\Uuid; + +interface Bitrix24PartnerInterface +{ + /** + * @return Uuid bitrix24 partner id + */ + public function getId(): Uuid; + + /** + * @return CarbonImmutable date and time bitrix24 partner create + */ + public function getCreatedAt(): CarbonImmutable; + + /** + * @return CarbonImmutable date and time bitrix24 partner last change + */ + public function getUpdatedAt(): CarbonImmutable; + + /** + * Get external id for bitrix24 partner + * + * Return external id for bitrix24 partner related entity in crm or erp - company or smart process + */ + public function getExternalId(): ?string; + + /** + * Get external id for bitrix24 partner + * + * Set external id for application installation related entity in crm or erp - company or smart process + * @param non-empty-string|null $externalId + * @throws InvalidArgumentException + */ + public function setExternalId(?string $externalId): void; + + /** + * Get application installation status + * + * active - active bitrix24 partner + * deleted - partner was deleted + * blocked - partner was blocked + */ + public function getStatus(): Bitrix24PartnerStatus; + + /** + * Change status to active for blocked bitrix24 partner accounts + * + * You can activate accounts only blocked state + * + * @param non-empty-string|null $comment + * @throws InvalidArgumentException + */ + public function markAsActive(?string $comment): void; + + /** + * Change status to blocked for bitrix24 partner account in state active + * + * You can block bitrix24 partner account if you need temporally stop work with this partner + * + * @param non-empty-string|null $comment + * @throws InvalidArgumentException + */ + public function markAsBlocked(?string $comment): void; + + /** + * Change status to deleted for bitrix24 partner account, use this for soft delete + * + * @param non-empty-string|null $comment + * @throws InvalidArgumentException + */ + public function markAsDeleted(?string $comment): void; + + /** + * Get comment + */ + public function getComment(): ?string; + + /** + * Get partner title + */ + public function getTitle(): string; + + /** + * Set partner title + * + * @param non-empty-string $title + * @throws InvalidArgumentException + */ + public function setTitle(string $title): void; + + /** + * Get partner site + */ + public function getSite(): ?string; + + /** + * Set partner site + * + * @param non-empty-string|null $site + * @throws InvalidArgumentException + */ + public function setSite(?string $site): void; + + /** + * Get partner phone + */ + public function getPhone(): ?PhoneNumber; + + /** + * Set partner phone + */ + public function setPhone(?PhoneNumber $phoneNumber): void; + + /** + * Get partner email + */ + public function getEmail(): ?string; + + /** + * Set partner email + * + * @param non-empty-string|null $email + * @throws InvalidArgumentException + */ + public function setEmail(?string $email): void; + + /** + * Get bitrix24 partner id + */ + public function getBitrix24PartnerId(): ?int; + + /** + * Set bitrix24 partner id + * @param positive-int|null $bitrix24PartnerId bitrix24 partner id from vendor site + * @throws InvalidArgumentException + */ + public function setBitrix24PartnerId(?int $bitrix24PartnerId): void; + + /** + * Get open line id + */ + public function getOpenLineId(): ?string; + + /** + * Set open line id + * @param non-empty-string|null $openLineId support open line identifier + * @throws InvalidArgumentException + */ + public function setOpenLineId(?string $openLineId): void; +} diff --git a/src/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerStatus.php b/src/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerStatus.php new file mode 100644 index 00000000..0071a2d7 --- /dev/null +++ b/src/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerStatus.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Entity; + +enum Bitrix24PartnerStatus: string +{ + case active = 'active'; // active bitrix24 partner + case deleted = 'deleted'; // partner was deleted + case blocked = 'blocked'; // partner was blocked +} \ No newline at end of file diff --git a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerBlockedEvent.php b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerBlockedEvent.php new file mode 100644 index 00000000..ce1e7495 --- /dev/null +++ b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerBlockedEvent.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class Bitrix24PartnerBlockedEvent extends Event +{ + public function __construct( + public readonly Uuid $bitrix24PartnerId, + public readonly CarbonImmutable $timestamp) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerCreatedEvent.php b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerCreatedEvent.php new file mode 100644 index 00000000..60752b94 --- /dev/null +++ b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerCreatedEvent.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class Bitrix24PartnerCreatedEvent extends Event +{ + public function __construct( + public readonly Uuid $bitrix24PartnerId, + public readonly CarbonImmutable $timestamp) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerDeletedEvent.php b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerDeletedEvent.php new file mode 100644 index 00000000..ead49c4e --- /dev/null +++ b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerDeletedEvent.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class Bitrix24PartnerDeletedEvent extends Event +{ + public function __construct( + public readonly Uuid $bitrix24PartnerId, + public readonly CarbonImmutable $timestamp) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerEmailChangedEvent.php b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerEmailChangedEvent.php new file mode 100644 index 00000000..c9d76fb2 --- /dev/null +++ b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerEmailChangedEvent.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class Bitrix24PartnerEmailChangedEvent extends Event +{ + public function __construct( + public readonly Uuid $bitrix24PartnerId, + public readonly CarbonImmutable $timestamp, + public readonly ?string $previousEmail, + public readonly ?string $currentEmail) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerExternalIdChangedEvent.php b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerExternalIdChangedEvent.php new file mode 100644 index 00000000..295d7ba2 --- /dev/null +++ b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerExternalIdChangedEvent.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class Bitrix24PartnerExternalIdChangedEvent extends Event +{ + public function __construct( + public readonly Uuid $bitrix24PartnerId, + public readonly CarbonImmutable $timestamp, + public readonly ?string $previousExternalId, + public readonly ?string $currentExternalId) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerOpenLineIdChangedEvent.php b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerOpenLineIdChangedEvent.php new file mode 100644 index 00000000..a6c7d916 --- /dev/null +++ b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerOpenLineIdChangedEvent.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class Bitrix24PartnerOpenLineIdChangedEvent extends Event +{ + public function __construct( + public readonly Uuid $bitrix24PartnerId, + public readonly CarbonImmutable $timestamp, + public readonly ?string $previousOpenLineId, + public readonly ?string $currentOpenLineId) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerPartnerIdChangedEvent.php b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerPartnerIdChangedEvent.php new file mode 100644 index 00000000..697282e7 --- /dev/null +++ b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerPartnerIdChangedEvent.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class Bitrix24PartnerPartnerIdChangedEvent extends Event +{ + public function __construct( + public readonly Uuid $bitrix24PartnerId, + public readonly CarbonImmutable $timestamp, + public readonly ?int $previousPartnerId, + public readonly ?int $currentPartnerId) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerPhoneChangedEvent.php b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerPhoneChangedEvent.php new file mode 100644 index 00000000..97948095 --- /dev/null +++ b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerPhoneChangedEvent.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Events; + +use Carbon\CarbonImmutable; +use libphonenumber\PhoneNumber; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class Bitrix24PartnerPhoneChangedEvent extends Event +{ + public function __construct( + public readonly Uuid $bitrix24PartnerId, + public readonly CarbonImmutable $timestamp, + public readonly ?PhoneNumber $previousPhone, + public readonly ?PhoneNumber $currentPhone) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerSiteChangedEvent.php b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerSiteChangedEvent.php new file mode 100644 index 00000000..7477c907 --- /dev/null +++ b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerSiteChangedEvent.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class Bitrix24PartnerSiteChangedEvent extends Event +{ + public function __construct( + public readonly Uuid $bitrix24PartnerId, + public readonly CarbonImmutable $timestamp, + public readonly ?string $previousSite, + public readonly ?string $currentSite) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerTitleChangedEvent.php b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerTitleChangedEvent.php new file mode 100644 index 00000000..50cae9dd --- /dev/null +++ b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerTitleChangedEvent.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class Bitrix24PartnerTitleChangedEvent extends Event +{ + public function __construct( + public readonly Uuid $bitrix24PartnerId, + public readonly CarbonImmutable $timestamp, + public readonly string $previousTitle, + public readonly string $currentTitle) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerUnblockedEvent.php b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerUnblockedEvent.php new file mode 100644 index 00000000..84d01860 --- /dev/null +++ b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerUnblockedEvent.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class Bitrix24PartnerUnblockedEvent extends Event +{ + public function __construct( + public readonly Uuid $bitrix24PartnerId, + public readonly CarbonImmutable $timestamp) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/Bitrix24Partners/Exceptions/Bitrix24PartnerNotFoundException.php b/src/Application/Contracts/Bitrix24Partners/Exceptions/Bitrix24PartnerNotFoundException.php new file mode 100644 index 00000000..47bee12a --- /dev/null +++ b/src/Application/Contracts/Bitrix24Partners/Exceptions/Bitrix24PartnerNotFoundException.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Exceptions; + +use Bitrix24\SDK\Core\Exceptions\BaseException; + +class Bitrix24PartnerNotFoundException extends BaseException +{ +} \ No newline at end of file diff --git a/src/Application/Contracts/Bitrix24Partners/Repository/Bitrix24PartnerRepositoryInterface.php b/src/Application/Contracts/Bitrix24Partners/Repository/Bitrix24PartnerRepositoryInterface.php new file mode 100644 index 00000000..7b78fbbb --- /dev/null +++ b/src/Application/Contracts/Bitrix24Partners/Repository/Bitrix24PartnerRepositoryInterface.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Repository; + +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts; +use Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Entity\Bitrix24PartnerInterface; +use Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Entity\Bitrix24PartnerStatus; +use Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Exceptions\Bitrix24PartnerNotFoundException; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Symfony\Component\Uid\Uuid; + +interface Bitrix24PartnerRepositoryInterface +{ + /** + * Save bitrix24 partner to persistence storage + * @throws InvalidArgumentException + */ + public function save(Bitrix24PartnerInterface $bitrix24Partner): void; + + /** + * Delete bitrix24 partner from persistence storage + * + * @throws Bitrix24PartnerNotFoundException + * @throws InvalidArgumentException + */ + public function delete(Uuid $uuid): void; + + /** + * Get bitrix24 partner by id + * + * @throws Bitrix24PartnerNotFoundException + */ + public function getById(Uuid $uuid): Bitrix24PartnerInterface; + + /** + * Find bitrix24 partner with bitrix24 partner id + * + * @param non-negative-int $bitrix24PartnerId + */ + public function findByBitrix24PartnerId(int $bitrix24PartnerId): ?Bitrix24PartnerInterface; + + /** + * Find bitrix24 partner by title + * + * @param non-empty-string $title + * @return Bitrix24PartnerInterface[] + * @throws InvalidArgumentException + */ + public function findByTitle(string $title): array; + + /** + * Find bitrix24 partner by external id + * + * External id its id in external system (erp/crm) its company id or smart-process item id + * + * @param non-empty-string $externalId + * @return Bitrix24PartnerInterface[] + * @throws InvalidArgumentException + */ + public function findByExternalId(string $externalId, ?Bitrix24PartnerStatus $bitrix24PartnerStatus = null): array; +} \ No newline at end of file diff --git a/src/Application/Contracts/ContactPersons/Docs/ContactPersons.md b/src/Application/Contracts/ContactPersons/Docs/ContactPersons.md new file mode 100644 index 00000000..d2e4461a --- /dev/null +++ b/src/Application/Contracts/ContactPersons/Docs/ContactPersons.md @@ -0,0 +1,101 @@ +# Contact Person entity + +Store information about person who installed application + +| Method | Return Type | Description | Throws | +|-------------------------------|-----------------------|-----------------------------------------------------------------------------|----------------------------| +| `getId()` | `Uuid` | Returns unique contact person id | - | +| `getStatus()` | `ContactPersonStatus` | Returns contact person status | - | +| `markAsActive()` | `void` | Sets contact person status to active | `InvalidArgumentException` | +| `markAsBlocked()` | `void` | Sets contact person status to blocked | `InvalidArgumentException` | +| `markAsDeleted()` | `void` | Sets contact person status to deleted (soft delete) | `InvalidArgumentException` | +| `getFullName()` | `FullName` | Returns contact person full name | - | +| `changeFullName()` | `void` | Changes contact person full name | - | +| `getCreatedAt()` | `CarbonImmutable` | Returns date and time contact person was created | - | +| `getUpdatedAt()` | `CarbonImmutable` | Returns date and time contact person was last updated | - | +| `getEmail()` | `?string` | Returns contact person email (if any) | - | +| `changeEmail()` | `void` | Changes contact person email | - | +| `markEmailAsVerified()` | `void` | Marks contact person email as verified | - | +| `getEmailVerifiedAt()` | `?CarbonImmutable` | Returns date and time email was verified (if verified) | - | +| `changeMobilePhone()` | `void` | Changes mobile phone for contact person | - | +| `getMobilePhone()` | `?PhoneNumber` | Returns contact person mobile phone (if any) | - | +| `getMobilePhoneVerifiedAt()` | `?CarbonImmutable` | Returns date and time mobile phone was verified (if verified) | - | +| `markMobilePhoneAsVerified()` | `void` | Marks contact person mobile phone as verified | - | +| `getComment()` | `?string` | Returns comment for this contact person (if any) | - | +| `setExternalId()` | `void` | Sets external id for contact person from external system | - | +| `getExternalId()` | `?string` | Returns external id for contact person (if any) | - | +| `getBitrix24UserId()` | `?int` | Returns bitrix24 user id if contact person mapped on bitrix24 user (if any) | - | +| `getBitrix24PartnerId()` | `?Uuid` | Returns bitrix24 partner id if contact person is bitrix24 partner employee | - | +| `setBitrix24PartnerId()` | `void` | Change bitrix24 partner id if contact person is bitrix24 partner employee | - | +| `getUserAgent()` | `?string` | Returns user agent for contact person | - | +| `getUserAgentReferer()` | `?string` | Returns user agent referer for contact person | - | +| `getUserAgentIp()` | `?IP` | Returns user agent IP for contact person | - | + +## Contact person state diagram + +```mermaid +stateDiagram-v2 + [*] --> Active: Active contact person\n after installation completed + Active --> Blocked : Contact person blocked or\nforcibly deactivated + Active --> Deleted : Application\n uninstalled + Blocked --> Active : Unblock contact person + Blocked --> Deleted : Delete blocked\n contact person + Deleted --> [*]: Contact person can be removed\n from persistence storage +``` + +## Repository methods + +- `public function save(ContactPersonInterface $contactPerson): void;` + - use case Create + - use case Block + - use case Unblock + - use case ChangeFullName + - use case ChangeEmail + - use case ChangeMobilePhone + - use case VerifyEmail + - use case VerifyMobilePhone + - use case AddComment + - use case LinkToExternalEntity + - use case LinkToBitrix24Partner + - use case UnlinkFromBitrix24Partner +- `public function delete(Uuid $uuid): void;` + - use case Delete +- `public function getById(Uuid $uuid): ContactPersonInterface;` + - use case Block + - use case Unblock + - use case ChangeFullName + - use case ChangeEmail + - use case ChangeMobilePhone + - use case VerifyEmail + - use case VerifyMobilePhone + - use case AddComment + - use case LinkToExternalEntity +- `public function findByEmail(string $email, ?ContactPersonStatus $contactPersonStatus = null, ?bool $isEmailVerified = null): array;` + - use case ChangeEmail + - use case VerifyEmail +- `public function findByPhone(PhoneNumber $phoneNumber, ?ContactPersonStatus $contactPersonStatus = null, ?bool $isPhoneVerified = null): array;` + - use case ChangeMobilePhone + - use case VerifyMobilePhone +- `public function findByExternalId(string $externalId, ?ContactPersonStatus $contactPersonStatus = null): array;` + - use case LinkToExternalEntity + +## Events + +```mermaid +%%{init: { 'logLevel': 'debug', 'theme': 'neutral' } }%% +timeline + title Contact person timeline + section Application installation period + Create new contact person when install start : Contact Person Created Event + section Active application period + Change contact person full name : Contact Person Full Name Changed Event + Change contact person email : Contact Person Email Changed Event + Change contact person mobile phone : Contact Person Mobile Phone Changed Event + Verify contact person email: Contact Person Email Verified Event + Verify contact person mobile phone: Contact Person Mobile Phone Verified Event + Block contact person : Contact Person Blocked Event + Unblock contact person : Contact Person Unblocked Event + Link contact person to external entity : Contact Person Linked To External Entity Event + section Application uninstall period + Delete contact person : Contact Person Deleted Event +``` \ No newline at end of file diff --git a/src/Application/Contracts/ContactPersons/Entity/ContactPersonInterface.php b/src/Application/Contracts/ContactPersons/Entity/ContactPersonInterface.php new file mode 100644 index 00000000..384c97f8 --- /dev/null +++ b/src/Application/Contracts/ContactPersons/Entity/ContactPersonInterface.php @@ -0,0 +1,150 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ContactPersons\Entity; + +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Carbon\CarbonImmutable; +use libphonenumber\PhoneNumber; +use Symfony\Component\Uid\Uuid; +use Darsyn\IP\Version\Multi as IP; + +interface ContactPersonInterface +{ + /** + * @return Uuid unique contact person id + */ + public function getId(): Uuid; + + /** + * @return ContactPersonStatus contact person status + */ + public function getStatus(): ContactPersonStatus; + + /** + * Set contact person status to active + * @param non-empty-string|null $comment + * @throws InvalidArgumentException + */ + public function markAsActive(?string $comment): void; + + /** + * Set contact person status to blocked + * @param non-empty-string|null $comment + * @throws InvalidArgumentException + */ + public function markAsBlocked(?string $comment): void; + + /** + * Set contact person status to deleted, use this for soft delete + * @param non-empty-string|null $comment + * @throws InvalidArgumentException + */ + public function markAsDeleted(?string $comment): void; + + /** + * @return FullName return contact person full name + */ + public function getFullName(): FullName; + + public function changeFullName(FullName $fullName): void; + + /** + * @return CarbonImmutable date and time contact person create + */ + public function getCreatedAt(): CarbonImmutable; + + /** + * @return CarbonImmutable date and time contact person change + */ + public function getUpdatedAt(): CarbonImmutable; + + /** + * @return string|null get contact person email + */ + public function getEmail(): ?string; + + public function changeEmail(?string $email, ?bool $isEmailVerified = null): void; + + /** + * @return void mark contact person email as verified (send check main) + */ + public function markEmailAsVerified(): void; + + /** + * @return CarbonImmutable|null is contact person email verified + */ + public function getEmailVerifiedAt(): ?CarbonImmutable; + + /** + * Change mobile phone for contact person + */ + public function changeMobilePhone(?PhoneNumber $phoneNumber, ?bool $isMobilePhoneVerified = null): void; + + public function getMobilePhone(): ?PhoneNumber; + + /** + * @return CarbonImmutable|null is contact person mobile phone verified + */ + public function getMobilePhoneVerifiedAt(): ?CarbonImmutable; + + /** + * @return void mark contact person mobile phone as verified (send check main) + */ + public function markMobilePhoneAsVerified(): void; + + /** + * @return non-empty-string|null get comment for this contact person + */ + public function getComment(): ?string; + + /** + * set external id for contact person from external system + */ + public function setExternalId(?string $externalId): void; + + /** + * get external id for contact person + */ + public function getExternalId(): ?string; + + /** + * @return int|null get bitrix24 user id if contact person mapped on bitrix24 user + */ + public function getBitrix24UserId(): ?int; + + /** + * @return Uuid|null get bitrix24 partner uuid if contact person is partner employee + */ + public function getBitrix24PartnerId(): ?Uuid; + + /** + * @param Uuid|null $uuid set bitrix24 partner uuid if contact person is partner employee + */ + public function setBitrix24PartnerId(?Uuid $uuid): void; + + /** + * get user agent for contact person, use for store metadata in consent agreements facts + */ + public function getUserAgent(): ?string; + + /** + * get user agent referer for contact person use for store metadata in consent agreements facts + */ + public function getUserAgentReferer(): ?string; + + /** + * get user agent ip for contact person use for store metadata in consent agreements facts + */ + public function getUserAgentIp(): ?IP; +} diff --git a/src/Application/Contracts/ContactPersons/Entity/ContactPersonStatus.php b/src/Application/Contracts/ContactPersons/Entity/ContactPersonStatus.php new file mode 100644 index 00000000..25ebd80b --- /dev/null +++ b/src/Application/Contracts/ContactPersons/Entity/ContactPersonStatus.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ContactPersons\Entity; + +enum ContactPersonStatus: string +{ + case active = 'active'; // active contact person + case deleted = 'deleted'; // the app has been removed from the portal + case blocked = 'blocked'; // developer forcibly deactivated the account +} \ No newline at end of file diff --git a/src/Application/Contracts/ContactPersons/Entity/FullName.php b/src/Application/Contracts/ContactPersons/Entity/FullName.php new file mode 100644 index 00000000..e1e3c6b4 --- /dev/null +++ b/src/Application/Contracts/ContactPersons/Entity/FullName.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ContactPersons\Entity; + +use Stringable; + +class FullName implements Stringable +{ + public function __construct( + public string $name, + public ?string $surname = null, + public ?string $patronymic = null + ) + { + if ($surname !== null) { + $this->surname = trim($surname); + } + + if ($this->patronymic !== null) { + $this->patronymic = trim((string) $patronymic); + } + } + + public function equal(self $fullName): bool + { + return $this->name === $fullName->name && $this->surname === $fullName->surname && $this->patronymic === $fullName->patronymic; + } + + public function __toString(): string + { + return sprintf('%s %s %s', $this->name, $this->surname, $this->patronymic); + } +} \ No newline at end of file diff --git a/src/Application/Contracts/ContactPersons/Events/ContactPersonBlockedEvent.php b/src/Application/Contracts/ContactPersons/Events/ContactPersonBlockedEvent.php new file mode 100644 index 00000000..ec909b0a --- /dev/null +++ b/src/Application/Contracts/ContactPersons/Events/ContactPersonBlockedEvent.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ContactPersons\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class ContactPersonBlockedEvent extends Event +{ + public function __construct( + public readonly Uuid $contactPersonId, + public readonly CarbonImmutable $timestamp) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/ContactPersons/Events/ContactPersonCreatedEvent.php b/src/Application/Contracts/ContactPersons/Events/ContactPersonCreatedEvent.php new file mode 100644 index 00000000..f1735cfb --- /dev/null +++ b/src/Application/Contracts/ContactPersons/Events/ContactPersonCreatedEvent.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ContactPersons\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class ContactPersonCreatedEvent extends Event +{ + public function __construct( + public readonly Uuid $contactPersonId, + public readonly CarbonImmutable $timestamp) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/ContactPersons/Events/ContactPersonDeletedEvent.php b/src/Application/Contracts/ContactPersons/Events/ContactPersonDeletedEvent.php new file mode 100644 index 00000000..473ac0c4 --- /dev/null +++ b/src/Application/Contracts/ContactPersons/Events/ContactPersonDeletedEvent.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ContactPersons\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class ContactPersonDeletedEvent extends Event +{ + public function __construct( + public readonly Uuid $contactPersonId, + public readonly CarbonImmutable $timestamp) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/ContactPersons/Events/ContactPersonEmailChangedEvent.php b/src/Application/Contracts/ContactPersons/Events/ContactPersonEmailChangedEvent.php new file mode 100644 index 00000000..49e4688e --- /dev/null +++ b/src/Application/Contracts/ContactPersons/Events/ContactPersonEmailChangedEvent.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ContactPersons\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class ContactPersonEmailChangedEvent extends Event +{ + public function __construct( + public readonly Uuid $contactPersonId, + public readonly CarbonImmutable $timestamp) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/ContactPersons/Events/ContactPersonEmailVerifiedEvent.php b/src/Application/Contracts/ContactPersons/Events/ContactPersonEmailVerifiedEvent.php new file mode 100644 index 00000000..081bdafc --- /dev/null +++ b/src/Application/Contracts/ContactPersons/Events/ContactPersonEmailVerifiedEvent.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ContactPersons\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class ContactPersonEmailVerifiedEvent extends Event +{ + public function __construct( + public readonly Uuid $contactPersonId, + public readonly CarbonImmutable $timestamp) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/ContactPersons/Events/ContactPersonFullNameChangedEvent.php b/src/Application/Contracts/ContactPersons/Events/ContactPersonFullNameChangedEvent.php new file mode 100644 index 00000000..8f75e03f --- /dev/null +++ b/src/Application/Contracts/ContactPersons/Events/ContactPersonFullNameChangedEvent.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ContactPersons\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class ContactPersonFullNameChangedEvent extends Event +{ + public function __construct( + public readonly Uuid $contactPersonId, + public readonly CarbonImmutable $timestamp) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/ContactPersons/Events/ContactPersonLinkedToExternalEntityEvent.php b/src/Application/Contracts/ContactPersons/Events/ContactPersonLinkedToExternalEntityEvent.php new file mode 100644 index 00000000..cc4c8b86 --- /dev/null +++ b/src/Application/Contracts/ContactPersons/Events/ContactPersonLinkedToExternalEntityEvent.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ContactPersons\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class ContactPersonLinkedToExternalEntityEvent extends Event +{ + public function __construct( + public readonly Uuid $contactPersonId, + public readonly CarbonImmutable $timestamp) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/ContactPersons/Events/ContactPersonMobilePhoneChangedEvent.php b/src/Application/Contracts/ContactPersons/Events/ContactPersonMobilePhoneChangedEvent.php new file mode 100644 index 00000000..af5594a8 --- /dev/null +++ b/src/Application/Contracts/ContactPersons/Events/ContactPersonMobilePhoneChangedEvent.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ContactPersons\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class ContactPersonMobilePhoneChangedEvent extends Event +{ + public function __construct( + public readonly Uuid $contactPersonId, + public readonly CarbonImmutable $timestamp) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/ContactPersons/Events/ContactPersonMobilePhoneVerifiedEvent.php b/src/Application/Contracts/ContactPersons/Events/ContactPersonMobilePhoneVerifiedEvent.php new file mode 100644 index 00000000..2a990d69 --- /dev/null +++ b/src/Application/Contracts/ContactPersons/Events/ContactPersonMobilePhoneVerifiedEvent.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ContactPersons\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class ContactPersonMobilePhoneVerifiedEvent extends Event +{ + public function __construct( + public readonly Uuid $contactPersonId, + public readonly CarbonImmutable $timestamp) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/ContactPersons/Events/ContactPersonUnblockedEvent.php b/src/Application/Contracts/ContactPersons/Events/ContactPersonUnblockedEvent.php new file mode 100644 index 00000000..2f3b0e7b --- /dev/null +++ b/src/Application/Contracts/ContactPersons/Events/ContactPersonUnblockedEvent.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ContactPersons\Events; + +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +class ContactPersonUnblockedEvent extends Event +{ + public function __construct( + public readonly Uuid $contactPersonId, + public readonly CarbonImmutable $timestamp) + { + } +} \ No newline at end of file diff --git a/src/Application/Contracts/ContactPersons/Exceptions/ContactPersonNotFoundException.php b/src/Application/Contracts/ContactPersons/Exceptions/ContactPersonNotFoundException.php new file mode 100644 index 00000000..94d9fc20 --- /dev/null +++ b/src/Application/Contracts/ContactPersons/Exceptions/ContactPersonNotFoundException.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ContactPersons\Exceptions; + +use Bitrix24\SDK\Core\Exceptions\BaseException; + +class ContactPersonNotFoundException extends BaseException +{ +} \ No newline at end of file diff --git a/src/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterface.php b/src/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterface.php new file mode 100644 index 00000000..880c7299 --- /dev/null +++ b/src/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterface.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\ContactPersons\Repository; + +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts; +use Bitrix24\SDK\Application\Contracts\ContactPersons\Entity\ContactPersonInterface; +use Bitrix24\SDK\Application\Contracts\ContactPersons\Entity\ContactPersonStatus; +use Bitrix24\SDK\Application\Contracts\ContactPersons\Exceptions\ContactPersonNotFoundException; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use libphonenumber\PhoneNumber; +use Symfony\Component\Uid\Uuid; + +interface ContactPersonRepositoryInterface +{ + /** + * Save contact person to persistence storage + */ + public function save(ContactPersonInterface $contactPerson): void; + + /** + * Delete contact person from persistence storage + * @throws ContactPersonNotFoundException + * @throws InvalidArgumentException + */ + public function delete(Uuid $uuid): void; + + /** + * Get contact person by id + * @throws ContactPersonNotFoundException + */ + public function getById(Uuid $uuid): ContactPersonInterface; + + /** + * Find contact persons with email and filter by status and isEmailVerified flag + * @param non-empty-string $email + * @return ContactPersonInterface[] + */ + public function findByEmail(string $email, ?ContactPersonStatus $contactPersonStatus = null, ?bool $isEmailVerified = null): array; + + /** + * Find contact persons with PhoneNumber and filter by status and isEmailVerified flag + * @return ContactPersonInterface[] + */ + public function findByPhone(PhoneNumber $phoneNumber, ?ContactPersonStatus $contactPersonStatus = null, ?bool $isPhoneVerified = null): array; + + /** + * Find contact person by external id + * + * One contact person can install application in different portals in different times, but in external system (erp/crm) its only one contact + * + * @param non-empty-string $externalId + * @return ContactPersonInterface[] + * @throws InvalidArgumentException + */ + public function findByExternalId(string $externalId, ?ContactPersonStatus $contactPersonStatus = null): array; +} \ No newline at end of file diff --git a/src/Application/Contracts/Events/AggregateRootEventsEmitterInterface.php b/src/Application/Contracts/Events/AggregateRootEventsEmitterInterface.php new file mode 100644 index 00000000..15ee1d3b --- /dev/null +++ b/src/Application/Contracts/Events/AggregateRootEventsEmitterInterface.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Contracts\Events; + +use Symfony\Contracts\EventDispatcher\Event; + +interface AggregateRootEventsEmitterInterface +{ + /** + * @return Event[] + */ + public function emitEvents(): array; +} \ No newline at end of file diff --git a/src/Application/PortalLicenseFamily.php b/src/Application/PortalLicenseFamily.php new file mode 100644 index 00000000..718fa953 --- /dev/null +++ b/src/Application/PortalLicenseFamily.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application; + +/** + * Portal license family enum + * @link https://training.bitrix24.com/rest_help/general/app_info.php + */ +enum PortalLicenseFamily: string +{ + case free = 'free'; + case basic = 'basic'; + case std = 'std'; + case pro = 'pro'; + case en = 'en'; + case nfr = 'nfr'; +} \ 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..e5d39aba --- /dev/null +++ b/src/Application/Requests/AbstractRequest.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Requests; + +use Symfony\Component\HttpFoundation\Request; + +abstract class AbstractRequest +{ + public function __construct(protected Request $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..f2ea13c8 --- /dev/null +++ b/src/Application/Requests/Events/AbstractEventRequest.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Requests\Events; + +use Bitrix24\SDK\Application\Requests\AbstractRequest; +use Symfony\Component\HttpFoundation\Request; + +abstract class AbstractEventRequest extends AbstractRequest implements EventInterface +{ + protected string $eventCode; + + protected int $timestamp; + + protected array $eventPayload; + + protected int $eventId; + + public function __construct(Request $request) + { + parent::__construct($request); + $payload = []; + parse_str($request->getContent(), $payload); + $this->eventPayload = $payload; + + $this->eventCode = $this->eventPayload['event']; + $this->timestamp = (int)$this->eventPayload['ts']; + $this->eventId = (int)$this->eventPayload['event_id']; + } + + public function getEventId(): int + { + return $this->eventId; + } + + public function getTimestamp(): int + { + return $this->timestamp; + } + + public function getEventCode(): string + { + return $this->eventCode; + } + + public function getEventPayload(): array + { + return $this->eventPayload; + } + + public function getAuth(): EventAuthItem + { + return new EventAuthItem($this->eventPayload['auth']); + } +} \ No newline at end of file diff --git a/src/Application/Requests/Events/EventAuthItem.php b/src/Application/Requests/Events/EventAuthItem.php new file mode 100644 index 00000000..57438567 --- /dev/null +++ b/src/Application/Requests/Events/EventAuthItem.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Requests\Events; + + +use Bitrix24\SDK\Application\ApplicationStatus; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException; +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read non-empty-string $access_token + * @property-read int $expires + * @property-read int $expires_in + * @property-read Scope $scope + * @property-read non-empty-string $domain + * @property-read non-empty-string $server_endpoint + * @property-read non-empty-string $client_endpoint + * @property-read non-empty-string $member_id + * @property-read ApplicationStatus $status + * @property-read int $user_id + * @property-read non-empty-string $application_token + */ +class EventAuthItem extends AbstractItem +{ + /** + * @throws UnknownScopeCodeException + * @throws InvalidArgumentException + */ + public function __get($offset) + { + return match ($offset) { + 'expires', 'expires_in' => (int)$this->data[$offset], + 'scope' => Scope::initFromString((string)$this->data[$offset]), + 'status' => ApplicationStatus::initFromString((string)$this->data[$offset]), + default => $this->data[$offset] ?? null, + }; + } +} \ No newline at end of file diff --git a/src/Application/Requests/Events/EventInterface.php b/src/Application/Requests/Events/EventInterface.php new file mode 100644 index 00000000..c425937e --- /dev/null +++ b/src/Application/Requests/Events/EventInterface.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Requests\Events; + + +use Bitrix24\SDK\Application\ApplicationStatus; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException; +use Bitrix24\SDK\Core\Result\AbstractItem; + +interface EventInterface +{ + public function getEventCode(): string; + + public function getAuth(): EventAuthItem; + + public function getEventPayload(): array; +} \ 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..b60af89c --- /dev/null +++ b/src/Application/Requests/Events/OnApplicationInstall/ApplicationData.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Requests\Events\OnApplicationInstall; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read string $VERSION + * @property-read string $ACTIVE + * @property-read string $INSTALLED + * @property-read string $LANGUAGE_ID + */ +class ApplicationData extends AbstractItem +{ +} \ No newline at end of file diff --git a/src/Application/Requests/Events/OnApplicationInstall/OnApplicationInstall.php b/src/Application/Requests/Events/OnApplicationInstall/OnApplicationInstall.php new file mode 100644 index 00000000..283b5b47 --- /dev/null +++ b/src/Application/Requests/Events/OnApplicationInstall/OnApplicationInstall.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Requests\Events\OnApplicationInstall; + +use Bitrix24\SDK\Application\Requests\Events\AbstractEventRequest; + +class OnApplicationInstall extends AbstractEventRequest +{ + public function getApplicationData(): ApplicationData + { + return new ApplicationData($this->eventPayload['data']); + } +} \ 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..72069390 --- /dev/null +++ b/src/Application/Requests/Events/OnApplicationUninstall/ApplicationData.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Requests\Events\OnApplicationUninstall; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read string $CLEAN + * @property-read string $LANGUAGE_ID + */ +class ApplicationData extends AbstractItem +{ +} \ No newline at end of file diff --git a/src/Application/Requests/Events/OnApplicationUninstall/OnApplicationUninstall.php b/src/Application/Requests/Events/OnApplicationUninstall/OnApplicationUninstall.php new file mode 100644 index 00000000..96855e9e --- /dev/null +++ b/src/Application/Requests/Events/OnApplicationUninstall/OnApplicationUninstall.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Requests\Events\OnApplicationUninstall; + +use Bitrix24\SDK\Application\Requests\Events\AbstractEventRequest; + +class OnApplicationUninstall extends AbstractEventRequest +{ + public function getApplicationData(): ApplicationData + { + return new ApplicationData($this->eventPayload['data']); + } +} \ 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..0896fc0e --- /dev/null +++ b/src/Application/Requests/Placement/PlacementRequest.php @@ -0,0 +1,110 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Application\Requests\Placement; + +use Bitrix24\SDK\Application\ApplicationStatus; +use Bitrix24\SDK\Core\Credentials\AuthToken; +use Bitrix24\SDK\Application\Requests\AbstractRequest; +use InvalidArgumentException; +use Symfony\Component\HttpFoundation\Request; + +class PlacementRequest extends AbstractRequest +{ + private readonly AuthToken $accessToken; + + private readonly string $memberId; + + private readonly ApplicationStatus $applicationStatus; + + private readonly string $code; + + /** + * @var array + */ + private readonly array $placementOptions; + + private readonly string $domainUrl; + + private readonly string $languageCode; + + /** + * + * @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 = AuthToken::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; + } + + public function getMemberId(): string + { + return $this->memberId; + } + + public function getAccessToken(): AuthToken + { + return $this->accessToken; + } + + public function getCode(): string + { + return $this->code; + } + + + public function getPlacementOptions(): array + { + return $this->placementOptions; + } + + + public function getDomainUrl(): string + { + return $this->domainUrl; + } + + + public function getLanguageCode(): string + { + return $this->languageCode; + } +} \ No newline at end of file diff --git a/src/Attributes/ApiBatchMethodMetadata.php b/src/Attributes/ApiBatchMethodMetadata.php new file mode 100644 index 00000000..08c765da --- /dev/null +++ b/src/Attributes/ApiBatchMethodMetadata.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Attributes; + +use Attribute; + +#[Attribute(Attribute::TARGET_METHOD)] +class ApiBatchMethodMetadata +{ + public function __construct( + public string $name, + public string $documentationUrl, + public ?string $description = null, + public bool $isDeprecated = false, + public ?string $deprecationMessage = null + ) + { + } +} \ No newline at end of file diff --git a/src/Attributes/ApiBatchServiceMetadata.php b/src/Attributes/ApiBatchServiceMetadata.php new file mode 100644 index 00000000..90b4bb47 --- /dev/null +++ b/src/Attributes/ApiBatchServiceMetadata.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Attributes; + +use Attribute; +use Bitrix24\SDK\Core\Credentials\Scope; + +#[Attribute(Attribute::TARGET_CLASS)] +class ApiBatchServiceMetadata +{ + public function __construct( + public Scope $scope, + public ?string $documentationUrl = null, + public ?string $description = null, + public bool $isDeprecated = false, + public ?string $deprecationMessage = null + ) + { + } +} \ No newline at end of file diff --git a/src/Attributes/ApiEndpointMetadata.php b/src/Attributes/ApiEndpointMetadata.php new file mode 100644 index 00000000..d7d433b8 --- /dev/null +++ b/src/Attributes/ApiEndpointMetadata.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Attributes; + +use Attribute; + +#[Attribute(Attribute::TARGET_METHOD)] +class ApiEndpointMetadata +{ + public function __construct( + public string $name, + public string $documentationUrl, + public ?string $description = null, + public bool $isDeprecated = false, + public ?string $deprecationMessage = null + ) + { + } +} \ No newline at end of file diff --git a/src/Attributes/ApiServiceMetadata.php b/src/Attributes/ApiServiceMetadata.php new file mode 100644 index 00000000..1ca6a15b --- /dev/null +++ b/src/Attributes/ApiServiceMetadata.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Attributes; + +use Attribute; +use Bitrix24\SDK\Core\Credentials\Scope; + +#[Attribute(Attribute::TARGET_CLASS)] +class ApiServiceMetadata +{ + public function __construct( + public Scope $scope, + public ?string $documentationUrl = null, + public ?string $description = null, + public bool $isDeprecated = false, + public ?string $deprecationMessage = null + ) + { + } +} \ No newline at end of file diff --git a/src/Attributes/Services/AttributesParser.php b/src/Attributes/Services/AttributesParser.php new file mode 100644 index 00000000..af8cb17c --- /dev/null +++ b/src/Attributes/Services/AttributesParser.php @@ -0,0 +1,150 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Attributes\Services; + + +use Bitrix24\SDK\Attributes\ApiBatchMethodMetadata; +use Bitrix24\SDK\Attributes\ApiBatchServiceMetadata; +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use ReflectionClass; +use Symfony\Component\Filesystem\Filesystem; +use Typhoon\Reflection\TyphoonReflector; +use function Typhoon\Type\stringify; + +readonly class AttributesParser +{ + public function __construct( + private TyphoonReflector $typhoonReflector, + private Filesystem $filesystem, + ) + { + } + + /** + * @param class-string[] $sdkClassNames + * @return array + */ + public function getSupportedInSdkApiMethods(array $sdkClassNames, string $sdkBaseDir): array + { + $supportedInSdkMethods = []; + foreach ($sdkClassNames as $className) { + $reflectionServiceClass = new ReflectionClass($className); + $apiServiceAttribute = $reflectionServiceClass->getAttributes(ApiServiceMetadata::class); + if ($apiServiceAttribute === []) { + continue; + } + $apiServiceAttribute = $apiServiceAttribute[0]; + /** + * @var ApiServiceMetadata $apiServiceAttrInstance + */ + $apiServiceAttrInstance = $apiServiceAttribute->newInstance(); + // process api service + $serviceMethods = $reflectionServiceClass->getMethods(); + foreach ($serviceMethods as $method) { + $attributes = $method->getAttributes(ApiEndpointMetadata::class); + foreach ($attributes as $attribute) { + /** + * @var ApiEndpointMetadata $instance + */ + $instance = $attribute->newInstance(); + + // find return type file name + $returnTypeFileName = null; + if ($method->getReturnType() !== null) { + /** @var @phpstan-ignore-next-line */ + $returnTypeName = $method->getReturnType()->getName(); + if (class_exists($returnTypeName)) { + $reflectionReturnType = new ReflectionClass($returnTypeName); + $returnTypeFileName = substr($this->filesystem->makePathRelative($reflectionReturnType->getFileName(), $sdkBaseDir), 0, -1); + } + } + + $supportedInSdkMethods[$instance->name] = [ + 'sdk_scope' => $apiServiceAttrInstance->scope->getScopeCodes() === [] ? '' : $apiServiceAttrInstance->scope->getScopeCodes()[0], + 'name' => $instance->name, + 'documentation_url' => $instance->documentationUrl, + 'description' => $instance->description, + 'is_deprecated' => $instance->isDeprecated, + 'deprecation_message' => $instance->deprecationMessage, + 'sdk_method_name' => $method->getName(), + 'sdk_method_file_name' => substr($this->filesystem->makePathRelative($method->getFileName(), $sdkBaseDir), 0, -1), + 'sdk_method_file_start_line' => $method->getStartLine(), + 'sdk_method_file_end_line' => $method->getEndLine(), + 'sdk_class_name' => $className, + /** @var @phpstan-ignore-next-line */ + 'sdk_return_type_class' => $method->getReturnType()?->getName(), + 'sdk_return_type_file_name' => $returnTypeFileName + ]; + } + } + } + return $supportedInSdkMethods; + } + + /** + * @param class-string[] $sdkClassNames + * @return array + */ + public function getSupportedInSdkBatchMethods(array $sdkClassNames): array + { + $supportedInSdkMethods = []; + foreach ($sdkClassNames as $className) { + $reflectionServiceClass = new ReflectionClass($className); + $apiServiceAttribute = $reflectionServiceClass->getAttributes(ApiBatchServiceMetadata::class); + if ($apiServiceAttribute === []) { + continue; + } + //try to get type information from phpdoc annotations + $typhoonClassMeta = $this->typhoonReflector->reflectClass($className); + /** + * @var ApiBatchServiceMetadata $apiServiceAttrInstance + */ + $apiServiceAttribute = $apiServiceAttribute[0]; + $apiServiceAttrInstance = $apiServiceAttribute->newInstance(); + // process api service + $serviceMethods = $reflectionServiceClass->getMethods(); + foreach ($serviceMethods as $method) { + $attributes = $method->getAttributes(ApiBatchMethodMetadata::class); + foreach ($attributes as $attribute) { + /** + * @var ApiBatchMethodMetadata $instance + */ + $instance = $attribute->newInstance(); + $sdkReturnTypeTyphoon = null; + if ($method->getReturnType() !== null) { + // get return type from phpdoc annotation + $sdkReturnTypeTyphoon = stringify($typhoonClassMeta->methods()[$method->getName()]->returnType()); + } + + $supportedInSdkMethods[$instance->name][] = [ + 'sdk_scope' => $apiServiceAttrInstance->scope->getScopeCodes()[0], + 'name' => $instance->name, + 'documentation_url' => $instance->documentationUrl, + 'description' => $instance->description, + 'is_deprecated' => $instance->isDeprecated, + 'deprecation_message' => $instance->deprecationMessage, + 'sdk_method_name' => $method->getName(), + 'sdk_method_file_name' => $method->getFileName(), + 'sdk_method_file_start_line' => $method->getStartLine(), + 'sdk_method_file_end_line' => $method->getEndLine(), + 'sdk_method_return_type_typhoon' => $sdkReturnTypeTyphoon, + 'sdk_class_name' => $className, + ]; + } + } + } + return $supportedInSdkMethods; + } +} \ No newline at end of file diff --git a/src/Core/ApiClient.php b/src/Core/ApiClient.php new file mode 100644 index 00000000..9f1df967 --- /dev/null +++ b/src/Core/ApiClient.php @@ -0,0 +1,202 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core; + +use Bitrix24\SDK\Core\Contracts\ApiClientInterface; +use Bitrix24\SDK\Core\Credentials\AuthToken; +use Bitrix24\SDK\Core\Credentials\Credentials; +use Bitrix24\SDK\Core\Credentials\WebhookUrl; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Response\DTO\RenewedAuthToken; +use Bitrix24\SDK\Infrastructure\HttpClient\RequestId\RequestIdGeneratorInterface; +use Fig\Http\Message\StatusCodeInterface; +use Psr\Log\LoggerInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; + +class ApiClient implements ApiClientInterface +{ + /** + * @const string + */ + protected const BITRIX24_OAUTH_SERVER_URL = 'https://oauth.bitrix.info'; + + /** + * @const string + */ + protected const SDK_VERSION = '2.0.0'; + + protected const SDK_USER_AGENT = 'bitrix24-php-sdk'; + + /** + * ApiClient constructor. + */ + public function __construct( + protected Credentials $credentials, + protected HttpClientInterface $client, + protected RequestIdGeneratorInterface $requestIdGenerator, + protected LoggerInterface $logger) + { + $this->logger->debug( + 'ApiClient.init', + [ + 'httpClientType' => $this->client::class, + ] + ); + } + + /** + * @return array + */ + protected function getDefaultHeaders(): array + { + return [ + 'Accept' => 'application/json', + 'Accept-Charset' => 'utf-8', + 'User-Agent' => sprintf('%s-v-%s-php-%s', self::SDK_USER_AGENT, self::SDK_VERSION, PHP_VERSION), + 'X-BITRIX24-PHP-SDK-PHP-VERSION' => PHP_VERSION, + 'X-BITRIX24-PHP-SDK-VERSION' => self::SDK_VERSION, + ]; + } + + public function getCredentials(): Credentials + { + return $this->credentials; + } + + /** + * @throws InvalidArgumentException + * @throws TransportExceptionInterface + * @throws TransportException + */ + public function getNewAuthToken(): RenewedAuthToken + { + $requestId = $this->requestIdGenerator->getRequestId(); + $this->logger->debug('getNewAuthToken.start', [ + 'requestId' => $requestId + ]); + if (!$this->getCredentials()->getApplicationProfile() instanceof \Bitrix24\SDK\Core\Credentials\ApplicationProfile) { + throw new InvalidArgumentException('application profile not set'); + } + + if (!$this->getCredentials()->getAuthToken() instanceof AuthToken) { + throw new InvalidArgumentException('access token in credentials not set'); + } + + $method = 'GET'; + $url = sprintf( + '%s/oauth/token/?%s', + $this::BITRIX24_OAUTH_SERVER_URL, + http_build_query( + [ + 'grant_type' => 'refresh_token', + 'client_id' => $this->getCredentials()->getApplicationProfile()->getClientId(), + 'client_secret' => $this->getCredentials()->getApplicationProfile()->getClientSecret(), + 'refresh_token' => $this->getCredentials()->getAuthToken()->getRefreshToken(), + $this->requestIdGenerator->getQueryStringParameterName() => $requestId + ] + ) + ); + + $requestOptions = [ + 'headers' => array_merge( + $this->getDefaultHeaders(), + [ + $this->requestIdGenerator->getHeaderFieldName() => $requestId + ] + ), + ]; + $response = $this->client->request($method, $url, $requestOptions); + $responseData = $response->toArray(false); + if ($response->getStatusCode() === StatusCodeInterface::STATUS_OK) { + $newAuthToken = RenewedAuthToken::initFromArray($responseData); + + $this->logger->debug('getNewAuthToken.finish', [ + 'requestId' => $requestId + ]); + return $newAuthToken; + } + + if ($response->getStatusCode() === StatusCodeInterface::STATUS_BAD_REQUEST) { + $this->logger->warning('getNewAuthToken.badRequest',[ + 'url'=> $url + ]); + throw new TransportException(sprintf('getting new access token failure: %s', $responseData['error'])); + } + + throw new TransportException('getting new access token failure with unknown http-status code %s', $response->getStatusCode()); + } + + /** + * @param array $parameters + * + * @throws TransportExceptionInterface + * @throws InvalidArgumentException + */ + public function getResponse(string $apiMethod, array $parameters = []): ResponseInterface + { + $requestId = $this->requestIdGenerator->getRequestId(); + $this->logger->info( + 'getResponse.start', + [ + 'apiMethod' => $apiMethod, + 'domainUrl' => $this->credentials->getDomainUrl(), + 'parameters' => $parameters, + 'requestId' => $requestId + ] + ); + + $method = 'POST'; + if ($this->getCredentials()->getWebhookUrl() instanceof WebhookUrl) { + $url = sprintf('%s/%s/', $this->getCredentials()->getWebhookUrl()->getUrl(), $apiMethod); + } else { + $url = sprintf('%s/rest/%s', $this->getCredentials()->getDomainUrl(), $apiMethod); + + if (!$this->getCredentials()->getAuthToken() instanceof AuthToken) { + throw new InvalidArgumentException('access token in credentials not found '); + } + + $parameters['auth'] = $this->getCredentials()->getAuthToken()->getAccessToken(); + } + + // duplicate request id in query string for current version of bitrix24 api + // vendor don't use request id from headers =( + $url .= '?' . $this->requestIdGenerator->getQueryStringParameterName() . '=' . $requestId; + $requestOptions = [ + 'json' => $parameters, + 'headers' => array_merge( + $this->getDefaultHeaders(), + [ + $this->requestIdGenerator->getHeaderFieldName() => $requestId + ] + ), + // disable redirects, try to catch portal change domain name event + 'max_redirects' => 0, + ]; + $response = $this->client->request($method, $url, $requestOptions); + + $this->logger->info( + 'getResponse.end', + [ + 'apiMethod' => $apiMethod, + 'responseInfo' => $response->getInfo(), + 'requestId' => $requestId + ] + ); + + return $response; + } +} \ No newline at end of file diff --git a/src/Core/ApiLevelErrorHandler.php b/src/Core/ApiLevelErrorHandler.php new file mode 100644 index 00000000..e5fad9cb --- /dev/null +++ b/src/Core/ApiLevelErrorHandler.php @@ -0,0 +1,165 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core; + +use Bitrix24\SDK\Core\Exceptions\AuthForbiddenException; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\MethodNotFoundException; +use Bitrix24\SDK\Core\Exceptions\OperationTimeLimitExceededException; +use Bitrix24\SDK\Core\Exceptions\QueryLimitExceededException; +use Bitrix24\SDK\Core\Exceptions\UserNotFoundOrIsNotActiveException; +use Bitrix24\SDK\Core\Exceptions\WrongAuthTypeException; +use Bitrix24\SDK\Services\Workflows\Exceptions\ActivityOrRobotAlreadyInstalledException; +use Bitrix24\SDK\Services\Workflows\Exceptions\ActivityOrRobotValidationFailureException; +use Bitrix24\SDK\Services\Workflows\Exceptions\WorkflowTaskAlreadyCompletedException; +use Psr\Log\LoggerInterface; + +/** + * Handle api-level errors and throw related exception + */ +class ApiLevelErrorHandler +{ + protected const ERROR_KEY = 'error'; + + protected const RESULT_KEY = 'result'; + + protected const RESULT_ERROR_KEY = 'result_error'; + + protected const ERROR_DESCRIPTION_KEY = 'error_description'; + + /** + * ApiLevelErrorHandler constructor. + */ + public function __construct(protected LoggerInterface $logger) + { + } + + /** + * @param array $responseBody + * + * @throws QueryLimitExceededException + * @throws BaseException + */ + public function handle(array $responseBody): void + { + // single query error response + if (array_key_exists(self::ERROR_KEY, $responseBody) && array_key_exists(self::ERROR_DESCRIPTION_KEY, $responseBody)) { + $this->handleError($responseBody); + } + + // error in batch response + if (!array_key_exists(self::RESULT_KEY, $responseBody) || (!is_array($responseBody[self::RESULT_KEY]))) { + return; + } + + if (array_key_exists(self::RESULT_ERROR_KEY, $responseBody[self::RESULT_KEY])) { + foreach ($responseBody[self::RESULT_KEY][self::RESULT_ERROR_KEY] as $cmdId => $errorData) { + $this->handleError($errorData, $cmdId); + } + } + } + + /** + * @throws MethodNotFoundException + * @throws QueryLimitExceededException + * @throws BaseException + */ + private function handleError(array $responseBody, ?string $batchCommandId = null): void + { + $errorCode = strtolower(trim((string)$responseBody[self::ERROR_KEY])); + $errorDescription = strtolower(trim((string)$responseBody[self::ERROR_DESCRIPTION_KEY])); + + $this->logger->debug( + 'handle.errorInformation', + [ + 'errorCode' => $errorCode, + 'errorDescription' => $errorDescription, + ] + ); + + $batchErrorPrefix = ''; + if ($batchCommandId !== null) { + $batchErrorPrefix = sprintf(' batch command id: %s', $batchCommandId); + } + + // todo send issues to bitrix24 + // fix errors without error_code responses + if ($errorCode === '' && strtolower($errorDescription) === strtolower('You can delete ONLY templates created by current application')) { + $errorCode = 'bizproc_workflow_template_access_denied'; + } + + if ($errorCode === '' && strtolower($errorDescription) === strtolower('No fields to update.')) { + $errorCode = 'bad_request_no_fields_to_update'; + } + + if ($errorCode === '' && strtolower($errorDescription) === strtolower('User is not found or is not active')) { + $errorCode = 'user_not_found_or_is_not_active'; + } + + switch ($errorCode) { + case 'error_task_completed': + throw new WorkflowTaskAlreadyCompletedException(sprintf('%s - %s', $errorCode, $errorDescription)); + case 'bad_request_no_fields_to_update': + throw new InvalidArgumentException(sprintf('%s - %s', $errorCode, $errorDescription)); + case 'access_denied': + case 'bizproc_workflow_template_access_denied': + throw new AuthForbiddenException(sprintf('%s - %s', $errorCode, $errorDescription)); + case 'query_limit_exceeded': + throw new QueryLimitExceededException(sprintf('query limit exceeded - too many requests %s', $batchErrorPrefix)); + case 'error_method_not_found': + throw new MethodNotFoundException(sprintf('api method not found %s %s', $errorDescription, $batchErrorPrefix)); + case 'operation_time_limit': + throw new OperationTimeLimitExceededException(sprintf('operation time limit exceeded %s %s', $errorDescription, $batchErrorPrefix)); + case 'error_activity_already_installed': + throw new ActivityOrRobotAlreadyInstalledException(sprintf('%s - %s', $errorCode, $errorDescription)); + case 'error_activity_validation_failure': + throw new ActivityOrRobotValidationFailureException(sprintf('%s - %s', $errorCode, $errorDescription)); + case 'user_not_found_or_is_not_active': + throw new UserNotFoundOrIsNotActiveException(sprintf('%s - %s', $errorCode, $errorDescription)); + case 'wrong_auth_type': + throw new WrongAuthTypeException(sprintf('%s - %s', $errorCode, $errorDescription)); + default: + throw new BaseException(sprintf('%s - %s %s', $errorCode, $errorDescription, $batchErrorPrefix)); + } + + // switch (strtoupper(trim($apiResponse['error']))) { +// case 'EXPIRED_TOKEN': +// throw new Bitrix24TokenIsExpiredException($errorMsg); +// case 'WRONG_CLIENT': +// case 'ERROR_OAUTH': +// $this->log->error($errorMsg, $this->getErrorContext()); +// throw new Bitrix24WrongClientException($errorMsg); +// case 'ERROR_METHOD_NOT_FOUND': +// $this->log->error($errorMsg, $this->getErrorContext()); +// throw new Bitrix24MethodNotFoundException($errorMsg); +// case 'INVALID_TOKEN': +// case 'INVALID_GRANT': +// $this->log->error($errorMsg, $this->getErrorContext()); +// throw new Bitrix24TokenIsInvalidException($errorMsg); + +// case 'PAYMENT_REQUIRED': +// $this->log->error($errorMsg, $this->getErrorContext()); +// throw new Bitrix24PaymentRequiredException($errorMsg); +// case 'NO_AUTH_FOUND': +// $this->log->error($errorMsg, $this->getErrorContext()); +// throw new Bitrix24PortalRenamedException($errorMsg); +// case 'INSUFFICIENT_SCOPE': +// $this->log->error($errorMsg, $this->getErrorContext()); +// throw new Bitrix24InsufficientScope($errorMsg); +// default: +// $this->log->error($errorMsg, $this->getErrorContext()); +// throw new Bitrix24ApiException($errorMsg); + } +} \ No newline at end of file diff --git a/src/Core/Batch.php b/src/Core/Batch.php new file mode 100644 index 00000000..8fd250a1 --- /dev/null +++ b/src/Core/Batch.php @@ -0,0 +1,852 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core; + +use Bitrix24\SDK\Core\Commands\Command; +use Bitrix24\SDK\Core\Commands\CommandCollection; +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Response\DTO\Pagination; +use Bitrix24\SDK\Core\Response\DTO\ResponseData; +use Bitrix24\SDK\Core\Response\DTO\Result; +use Bitrix24\SDK\Core\Response\DTO\Time; +use Bitrix24\SDK\Core\Response\Response; +use Generator; +use Psr\Log\LoggerInterface; + +/** + * Class Batch + * + * @package Bitrix24\SDK\Core + */ +class Batch implements BatchOperationsInterface +{ + protected const MAX_BATCH_PACKET_SIZE = 50; + + protected const MAX_ELEMENTS_IN_PAGE = 50; + + protected CommandCollection $commands; + + /** + * Batch constructor. + */ + public function __construct(private readonly CoreInterface $core, private readonly LoggerInterface $logger) + { + $this->commands = new CommandCollection(); + } + + /** + * Clear api commands collection + */ + protected function clearCommands(): void + { + $this->logger->debug( + 'clearCommands.start', + [ + 'commandsCount' => $this->commands->count(), + ] + ); + $this->commands = new CommandCollection(); + $this->logger->debug('clearCommands.finish'); + } + + /** + * Add entity items with batch call + * + * @param array $entityItems + * + * @return Generator|ResponseData[] + * @throws BaseException + */ + public function addEntityItems(string $apiMethod, array $entityItems): Generator + { + $this->logger->debug( + 'addEntityItems.start', + [ + 'apiMethod' => $apiMethod, + 'entityItems' => $entityItems, + ] + ); + + try { + $this->clearCommands(); + foreach ($entityItems as $cnt => $item) { + $this->registerCommand($apiMethod, $item); + } + + foreach ($this->getTraversable(true) as $cnt => $addedItemResult) { + yield $cnt => $addedItemResult; + } + } catch (\Throwable $throwable) { + $errorMessage = sprintf('batch add entity items: %s', $throwable->getMessage()); + $this->logger->error( + $errorMessage, + [ + 'trace' => $throwable->getTrace(), + ] + ); + + throw new BaseException($errorMessage, $throwable->getCode(), $throwable); + } + + $this->logger->debug('addEntityItems.finish'); + } + + /** + * Delete entity items with batch call + * + * @param array $entityItemId + * + * @return Generator|ResponseData[] + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function deleteEntityItems(string $apiMethod, array $entityItemId): Generator + { + $this->logger->debug( + 'deleteEntityItems.start', + [ + 'apiMethod' => $apiMethod, + 'entityItems' => $entityItemId, + ] + ); + + try { + $this->clearCommands(); + foreach ($entityItemId as $cnt => $itemId) { + if (!is_int($itemId)) { + throw new InvalidArgumentException( + sprintf( + 'invalid type «%s» of entity id «%s» at position %s, entity id must be integer type', + gettype($itemId), + $itemId, + $cnt + ) + ); + } + + $this->registerCommand($apiMethod, ['ID' => $itemId]); + } + + foreach ($this->getTraversable(true) as $cnt => $deletedItemResult) { + yield $cnt => $deletedItemResult; + } + } catch (InvalidArgumentException $exception) { + $errorMessage = sprintf('batch delete entity items: %s', $exception->getMessage()); + $this->logger->error( + $errorMessage, + [ + 'trace' => $exception->getTrace(), + ] + ); + throw $exception; + } catch (\Throwable $exception) { + $errorMessage = sprintf('batch delete entity items: %s', $exception->getMessage()); + $this->logger->error( + $errorMessage, + [ + 'trace' => $exception->getTrace(), + ] + ); + + throw new BaseException($errorMessage, $exception->getCode(), $exception); + } + + $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 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) + ); + } + + $cmdArguments = [ + 'id' => $entityItemId, + 'fields' => $entityItem['fields'] + ]; + if (array_key_exists('params', $entityItem)) { + $cmdArguments['params'] = $entityItem['params']; + } + + $this->registerCommand($apiMethod, $cmdArguments); + } + + 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 + * + * @param array $parameters + * @param callable|null $callback not implemented + * + * @throws \Exception + */ + protected function registerCommand( + string $apiMethod, + array $parameters = [], + ?string $commandName = null, + callable $callback = null + ): void + { + $this->logger->debug( + 'registerCommand.start', + [ + 'apiMethod' => $apiMethod, + 'parameters' => $parameters, + 'commandName' => $commandName, + ] + ); + + $this->commands->attach(new Command($apiMethod, $parameters, $commandName)); + + $this->logger->debug( + 'registerCommand.finish', + [ + 'commandsCount' => $this->commands->count(), + ] + ); + } + + /** + * @param array $order + * + * @return array|string[] + */ + protected function getReverseOrder(array $order): array + { + $this->logger->debug( + 'getReverseOrder.start', + [ + 'order' => $order, + ] + ); + $reverseOrder = null; + + if ($order === []) { + $reverseOrder = ['ID' => 'DESC']; + } else { + $order = array_change_key_case($order, CASE_UPPER); + $oldDirection = array_values($order)[0]; + $newOrderDirection = $oldDirection === 'ASC' ? 'DESC' : 'ASC'; + + $reverseOrder[array_key_first($order)] = $newOrderDirection; + } + + $this->logger->debug( + 'getReverseOrder.finish', + [ + 'order' => $reverseOrder, + ] + ); + + return $reverseOrder; + } + + /** + * Get traversable list without count elements + * + * @param array $order + * @param array $filter + * @param array $select + * + * @return \Generator + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + */ + public function getTraversableList( + string $apiMethod, + array $order, + array $filter, + array $select, + ?int $limit = null, + ?array $additionalParameters = null + ): Generator + { + $this->logger->debug( + 'getTraversableList.start', + [ + 'apiMethod' => $apiMethod, + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'limit' => $limit, + 'additionalParameters' => $additionalParameters, + ] + ); + + // strategy.3 — ID filter, batch, no count, order + // — ✅ отключён подсчёт количества элементов в выборке + // — ⚠️ ID элементов в выборке возрастает, т.е. была сделана сортировка результатов по ID + // — используем batch + // — последовательное выполнение запросов + // + // Задел по оптимизации + // — ограниченное использование параллельных запросов + // + // Запросы отправляются к серверу последовательно с параметром "order": {"ID": "ASC"} (сортировка по возрастанию ID). + // Т.к. результаты отсортированы по возрастанию ID, то их можно объеденить в батч-запросы с отключённым подсчётом количества элементов в каждом. + // + // Порядок формирования фильтра: + // + // взяли фильтр с «прямой» сортировкой и получили первый ID + // взяли фильтр с «обратной» сортировкой и получили последний ID + // Т.к. ID монотонно возрастает, то делаем предположение, что все страницы заполнены элементами равномерно, на самом деле там будут «дыры» из-за мастер-мастер репликации и удалённых элементов. т.е. в результирующих выборках не всегда будет ровно 50 элементов. + // из готовых фильтров формируем выборки и упаковываем их в батч-команды. + // по возможности, батч-запросы выполняются параллельно + + // получили первый id элемента в выборке по фильтру + // todo проверили, что это *.list команда + // todo проверили, что в селекте есть ID, т.е. разработчик понимает, что ID используется + // todo проверили, что сортировка задана как "order": {"ID": "ASC"} т.е. разработчик понимает, что данные придут в таком порядке + // todo проверили, что если есть limit, то он >1 + // todo проверили, что в фильтре нет поля ID, т.к. мы с ним будем работать + + $params = [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => 0, + ]; + + // data structures for crm.items.* is little different =\ + $isCrmItemsInBatch = false; + if ($additionalParameters !== null) { + if (array_key_exists('entityTypeId', $additionalParameters)) { + $isCrmItemsInBatch = true; + } + + $params = array_merge($params, $additionalParameters); + } + + $keyId = $isCrmItemsInBatch ? 'id' : 'ID'; + + $response = $this->core->call($apiMethod, $params); + $totalElementsCount = $response->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 ($response->getResponseData()->getResult() as $listElement) { + ++$elementsCounter; + if ($limit !== null && $elementsCounter > $limit) { + return; + } + + yield $listElement; + } + + $this->logger->debug('getTraversableList.finish'); + + return; + } + + // filtered elements count more than one result page(50 elements) + // return first page + $lastElementIdInFirstPage = null; + if ($isCrmItemsInBatch) { + foreach ($response->getResponseData()->getResult()['items'] as $listElement) { + ++$elementsCounter; + $lastElementIdInFirstPage = (int)$listElement[$keyId]; + if ($limit !== null && $elementsCounter > $limit) { + return; + } + + yield $listElement; + } + } else { + foreach ($response->getResponseData()->getResult() as $listElement) { + ++$elementsCounter; + $lastElementIdInFirstPage = (int)$listElement[$keyId]; + if ($limit !== null && $elementsCounter > $limit) { + return; + } + + yield $listElement; + } + } + + $this->clearCommands(); + if (!in_array($keyId, $select, true)) { + $select[] = $keyId; + } + + // getLastElementId in filtered result + $params = [ + 'order' => $this->getReverseOrder($order), + 'filter' => $filter, + 'select' => $select, + 'start' => 0, + ]; + if ($additionalParameters !== null) { + $params = array_merge($params, $additionalParameters); + } + + $lastResultPage = $this->core->call($apiMethod, $params); + if ($isCrmItemsInBatch) { + $lastElementId = (int)$lastResultPage->getResponseData()->getResult()['items'][0][$keyId]; + } else { + $lastElementId = (int)$lastResultPage->getResponseData()->getResult()[0][$keyId]; + } + + // 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 + ++$lastElementIdInFirstPage; + for ($startId = $lastElementIdInFirstPage; $startId <= $lastElementId; $startId += self::MAX_ELEMENTS_IN_PAGE) { + $this->logger->debug('registerCommand.item', [ + 'startId' => $startId, + 'lastElementId' => $lastElementId, + 'delta' => $lastElementId - $startId, + ]); + + $delta = $lastElementId - $startId; + $isLastPage = false; + if ($delta > self::MAX_ELEMENTS_IN_PAGE) { + // ignore + // - master–master replication with id + // - deleted elements + $lastElementIdInPage = $startId + self::MAX_ELEMENTS_IN_PAGE; + } else { + $lastElementIdInPage = $lastElementId; + $isLastPage = true; + } + + $params = [ + 'order' => $order, + 'filter' => $this->updateFilterForBatch($keyId, $startId, $lastElementIdInPage, $isLastPage, $filter), + 'select' => $select, + 'start' => -1, + ]; + if ($additionalParameters !== null) { + $params = array_merge($params, $additionalParameters); + } + + $this->registerCommand($apiMethod, $params); + } + + $this->logger->debug( + 'getTraversableList.commandsRegistered', + [ + 'commandsCount' => $this->commands->count(), + ] + ); + + // iterate batch queries, max: 50 results per 50 elements in each result + foreach ($this->getTraversable(true) as $queryCnt => $queryResultData) { + /** + * @var $queryResultData ResponseData + */ + $this->logger->debug( + 'getTraversableList.batchResultItem', + [ + 'batchCommandItemNumber' => $queryCnt, + 'nextItem' => $queryResultData->getPagination()->getNextItem(), + 'durationTime' => $queryResultData->getTime()->duration, + ] + ); + + // iterate items in batch query result + if ($isCrmItemsInBatch) { + foreach ($queryResultData->getResult()['items'] as $listElement) { + ++$elementsCounter; + if ($limit !== null && $elementsCounter > $limit) { + return; + } + + yield $listElement; + } + } else { + foreach ($queryResultData->getResult() as $listElement) { + ++$elementsCounter; + if ($limit !== null && $elementsCounter > $limit) { + return; + } + + yield $listElement; + } + } + + } + + $this->logger->debug('getTraversableList.finish'); + } + + /** + * @param array $oldFilter + * + * @return array + */ + protected function updateFilterForBatch(string $keyId, int $startElementId, int $lastElementId, bool $isLastPage, array $oldFilter): array + { + $this->logger->debug('updateFilterForBatch.start', [ + 'startElementId' => $startElementId, + 'lastElementId' => $lastElementId, + 'isLastPage' => $isLastPage, + 'oldFilter' => $oldFilter, + 'key' => $keyId, + ]); + + $filter = array_merge( + $oldFilter, + [ + sprintf('>=%s', $keyId) => $startElementId, + $isLastPage ? sprintf('<=%s', $keyId) : sprintf('<%s', $keyId) => $lastElementId, + ] + ); + $this->logger->debug('updateFilterForBatch.finish', [ + 'filter' => $filter, + ]); + + return $filter; + } + + /** + * batch wrapper for *.list methods + * + * work with start item position and elements count + * + * @param array $order + * @param array $filter + * @param array $select + * + * @return Generator + * @throws BaseException + * @throws Exceptions\TransportException + * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + * @throws \Exception + */ + public function getTraversableListWithCount( + string $apiMethod, + array $order, + array $filter, + array $select, + ?int $limit = null + ): Generator + { + $this->logger->debug( + 'getTraversableListWithCount.start', + [ + 'apiMethod' => $apiMethod, + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'limit' => $limit, + ] + ); + $this->clearCommands(); + + // get total elements count + $response = $this->core->call( + $apiMethod, + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => 0, + ] + ); + + $nextItem = $response->getResponseData()->getPagination()->getNextItem(); + $total = $response->getResponseData()->getPagination()->getTotal(); + + $this->logger->debug( + 'getTraversableListWithCount.calculateCommandsRange', + [ + 'nextItem' => $nextItem, + 'totalItems' => $total, + ] + ); + + if ($total > self::MAX_ELEMENTS_IN_PAGE && $nextItem !== null) { + //more than one page in results - register list commands + for ($startItem = 0; $startItem <= $total; $startItem += $nextItem) { + $this->registerCommand( + $apiMethod, + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $startItem, + ] + ); + if ($limit !== null && $limit < $startItem) { + break; + } + } + } else { + // one page in results + $this->registerCommand( + $apiMethod, + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => 0, + ] + ); + } + + $this->logger->debug( + 'getTraversableListWithCount.commandsRegistered', + [ + 'commandsCount' => $this->commands->count(), + 'totalItemsToSelect' => $total, + ] + ); + + // iterate batch queries, max: 50 results per 50 elements in each result + $elementsCounter = 0; + foreach ($this->getTraversable(true) as $queryCnt => $queryResultData) { + /** + * @var $queryResultData ResponseData + */ + $this->logger->debug( + 'getTraversableListWithCount.batchResultItem', + [ + 'batchCommandItemNumber' => $queryCnt, + 'nextItem' => $queryResultData->getPagination()->getNextItem(), + 'durationTime' => $queryResultData->getTime()->duration, + ] + ); + // iterate items in batch query result + foreach ($queryResultData->getResult() as $listElement) { + ++$elementsCounter; + if ($limit !== null && $elementsCounter > $limit) { + return; + } + + yield $listElement; + } + } + + $this->logger->debug('getTraversableListWithCount.finish'); + } + + /** + * + * @return Generator + * @throws BaseException + * @throws Exceptions\TransportException + * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface + * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + * @throws \Exception + */ + protected function getTraversable(bool $isHaltOnError): Generator + { + $this->logger->debug( + 'getTraversable.start', + [ + 'isHaltOnError' => $isHaltOnError, + ] + ); + + foreach ($this->getTraversableBatchResults($isHaltOnError) as $batchItem => $traversableBatchResult) { + /** + * @var $batchResult Response + */ + $this->logger->debug( + 'getTraversable.batchResultItem.processStart', + [ + 'batchItemNumber' => $batchItem, + 'batchApiCommand' => $traversableBatchResult->getApiCommand()->getApiMethod(), + 'batchApiCommandId' => $traversableBatchResult->getApiCommand()->getId(), + ] + ); + // todo try to multiplex requests + $response = $traversableBatchResult->getResponseData(); + + // single queries + // todo handle error field + $resultDataItems = $response->getResult()['result']; + $resultQueryTimeItems = $response->getResult()['result_time']; + + // list queries + //todo handle result_error for list queries + $resultNextItems = $response->getResult()['result_next']; + $totalItems = $response->getResult()['result_total']; + foreach ($resultDataItems as $singleQueryKey => $singleQueryResult) { + if (!is_array($singleQueryResult)) { + $singleQueryResult = [$singleQueryResult]; + } + + if (!array_key_exists($singleQueryKey, $resultQueryTimeItems)) { + throw new BaseException(sprintf('query time with key %s not found', $singleQueryKey)); + } + + $nextItem = null; + if ($resultNextItems !== null && array_key_exists($singleQueryKey, $resultNextItems)) { + $nextItem = $resultNextItems[$singleQueryKey]; + } + + $total = null; + if ($totalItems !== null && count($totalItems) > 0) { + $total = $totalItems[$singleQueryKey]; + } + + yield new ResponseData( + $singleQueryResult, + Time::initFromResponse($resultQueryTimeItems[$singleQueryKey]), + new Pagination($nextItem, $total) + ); + } + + $this->logger->debug('getTraversable.batchResult.processFinish'); + } + + $this->logger->debug('getTraversable.finish'); + } + + /** + * + * @return Generator + * @throws BaseException + * @throws Exceptions\TransportException + */ + private function getTraversableBatchResults(bool $isHaltOnError): Generator + { + $this->logger->debug( + 'getTraversableBatchResults.start', + [ + 'commandsCount' => $this->commands->count(), + 'isHaltOnError' => $isHaltOnError, + ] + ); + + // todo check unique names if exists + // конвертируем во внутренние представление батч-команд + $apiCommands = $this->convertToApiCommands(); + $batchQueryCounter = 0; + while (count($apiCommands)) { + $batchQuery = array_splice($apiCommands, 0, self::MAX_BATCH_PACKET_SIZE); + $this->logger->debug( + 'getTraversableBatchResults.batchQuery', + [ + 'batchQueryNumber' => $batchQueryCounter, + 'queriesCount' => count($batchQuery), + ] + ); + // batch call + $batchResult = $this->core->call('batch', ['halt' => $isHaltOnError, 'cmd' => $batchQuery]); + // todo analyze batch result and halt on error + + ++$batchQueryCounter; + yield $batchResult; + } + + $this->logger->debug('getTraversableBatchResults.finish'); + } + + /** + * @return array + */ + private function convertToApiCommands(): array + { + $apiCommands = []; + foreach ($this->commands as $command) { + $apiCommands[$command->getId()] = sprintf( + '%s?%s', + $command->getApiMethod(), + http_build_query($command->getParameters()) + ); + } + + return $apiCommands; + } +} \ No newline at end of file diff --git a/src/Core/BulkItemsReader/BulkItemsReader.php b/src/Core/BulkItemsReader/BulkItemsReader.php new file mode 100644 index 00000000..d91a1fff --- /dev/null +++ b/src/Core/BulkItemsReader/BulkItemsReader.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\BulkItemsReader; + +use Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface; +use Generator; +use Psr\Log\LoggerInterface; + +class BulkItemsReader implements BulkItemsReaderInterface +{ + public function __construct(protected BulkItemsReaderInterface $readStrategy, protected LoggerInterface $logger) + { + } + + /** + * + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function getTraversableList(string $apiMethod, array $order, array $filter, array $select, ?int $limit = null): Generator + { + foreach ($this->readStrategy->getTraversableList($apiMethod, $order, $filter, $select, $limit) as $cnt => $item) { + yield $cnt => $item; + } + } +} + diff --git a/src/Core/BulkItemsReader/BulkItemsReaderBuilder.php b/src/Core/BulkItemsReader/BulkItemsReaderBuilder.php new file mode 100644 index 00000000..449eaa42 --- /dev/null +++ b/src/Core/BulkItemsReader/BulkItemsReaderBuilder.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\BulkItemsReader; + +use Bitrix24\SDK\Core\BulkItemsReader\ReadStrategies\FilterWithBatchWithoutCountOrder; +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +use Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Psr\Log\LoggerInterface; + +class BulkItemsReaderBuilder +{ + protected BulkItemsReaderInterface $readStrategy; + + public function __construct(protected CoreInterface $core, protected BatchOperationsInterface $batch, protected LoggerInterface $logger) + { + $this->readStrategy = $this->getOptimalReadStrategy(); + } + + + public function withReadStrategy(BulkItemsReaderInterface $bulkItemsReader): BulkItemsReaderBuilder + { + $this->readStrategy = $bulkItemsReader; + + return $this; + } + + /** + * Get optimal read strategy based on integration tests with time and performance benchmarks + */ + protected function getOptimalReadStrategy(): BulkItemsReaderInterface + { + return new FilterWithBatchWithoutCountOrder($this->batch, $this->logger); + } + + public function build(): BulkItemsReaderInterface + { + return new BulkItemsReader($this->readStrategy, $this->logger); + } +} \ No newline at end of file diff --git a/src/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrder.php b/src/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrder.php new file mode 100644 index 00000000..b0cf76da --- /dev/null +++ b/src/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrder.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\BulkItemsReader\ReadStrategies; + +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +use Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface; +use Generator; +use Psr\Log\LoggerInterface; + +class FilterWithBatchWithoutCountOrder implements BulkItemsReaderInterface +{ + public function __construct(private readonly BatchOperationsInterface $batch, private readonly LoggerInterface $log) + { + } + + /** + * + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function getTraversableList(string $apiMethod, array $order, array $filter, array $select, ?int $limit = null): Generator + { + $this->log->debug('FilterWithBatchWithoutCountOrder.getTraversableList.start', [ + 'apiMethod' => $apiMethod, + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'limit' => $limit, + ]); + + foreach ($this->batch->getTraversableList($apiMethod, $order, $filter, $select, $limit) as $cnt => $resultItem) { + yield $cnt => $resultItem; + } + + $this->log->debug('FilterWithBatchWithoutCountOrder.getTraversableList.finish'); + } +} \ No newline at end of file diff --git a/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php b/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php new file mode 100644 index 00000000..97a10e48 --- /dev/null +++ b/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php @@ -0,0 +1,204 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\BulkItemsReader\ReadStrategies; + +use Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Generator; +use Psr\Log\LoggerInterface; + +class FilterWithoutBatchWithoutCountOrder implements BulkItemsReaderInterface +{ + public function __construct(private readonly CoreInterface $core, private readonly LoggerInterface $log) + { + } + + /** + * + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function getTraversableList(string $apiMethod, array $order, array $filter, array $select, ?int $limit = null): Generator + { + $this->log->debug('FilterWithoutBatchWithoutCountOrder.getTraversableList.start', [ + 'apiMethod' => $apiMethod, + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'limit' => $limit, + ]); + + // Дефолтная стратегия из документации https://dev.1c-bitrix.ru/rest_help/rest_sum/start.php + // + //Особенности: + //— ✅ отключён подсчёт количества элементов в выборке + //— ⚠️ ID элементов в выборке возрастает, т.е. была сделана сортировка результатов по ID + //— не используем batch + //— ❗️ парсим ответ сервера для получения следующего ID → проблемы с распараллеливанием запросов + //— последовательное выполнение запросов + // + //Задел по оптимизации + //— ограниченное использование параллельных запросов + // + // Запросы отправляются к серверу последовательно с параметром "order": {"ID": "ASC"} (сортировка по возрастанию ID), + // и в каждом последующем запросе используются результаты предыдущего (фильтрация по ID, где ID > максимального ID в результатах + // предыдущего запроса). + // + // При этом для ускорения используется параметр start = -1 для отключения затратной по времени операции расчета общего + // количества записей (поле total), которое по умолчанию возвращается в каждом ответе сервера при вызове методов вида *.list. + // + // В потенциале для ускорения можно попытаться параллельно передвигаться по списку сущностей в два потока: + // с начала списка и с конца, продолжая получать страницы, пока ID в двух потоках не пересекутся. + // Такой способ, возможно, будет давать двукратное ускорение до тех пор, пока не будет исчерпан пул запросов к серверу и не + // потребуется включить throttling. + + + // get total elements count + + + // получили первый id элемента в выборке по фильтру + // todo проверили, что это *.list команда + // todo проверили, что в селекте есть ID, т.е. разработчик понимает, что ID используется + // todo проверили, что сортировка задана как "order": {"ID": "ASC"} т.е. разработчик понимает, что данные придут в таком порядке + // todo проверили, что если есть limit, то он >1 + // todo проверили, что в фильтре нет поля ID, т.к. мы с ним будем работать + + + $firstElementId = $this->getFirstElementId($apiMethod, $filter, $select); + if ($firstElementId === null) { + $this->log->debug('FilterWithoutBatchWithoutCountOrder.getTraversableList.emptySelect'); + + return; + } + + $lastElementId = $this->getLastElementId($apiMethod, $filter, $select); + if ($lastElementId === null) { + $this->log->debug('FilterWithoutBatchWithoutCountOrder.getTraversableList.emptySelect'); + + return; + } + + // делаем запросы к Б24 + // todo учесть ретраии + // todo ограничения по количеству запросов в секунду + пул запросов + $currentElementId = $firstElementId; + $isStop = false; + while (!$isStop) { + $filterQuery = '>ID'; + if ($currentElementId === $firstElementId) { + $filterQuery = '>=ID'; + } + + $resultPage = $this->core->call( + $apiMethod, + [ + 'order' => ['ID' => 'ASC'], + 'filter' => array_merge( + [$filterQuery => $currentElementId], + $filter + ), + 'select' => array_unique(array_merge(['ID'], $select)), + 'start' => -1, + ] + ); + + + foreach ($resultPage->getResponseData()->getResult() as $cnt => $item) { + + + $currentElementId = (int)$item['ID']; + yield $cnt => $item; + } + + $this->log->debug('FilterWithoutBatchWithoutCountOrder.step', [ + 'duration' => $resultPage->getResponseData()->getTime()->duration, + 'currentElementId' => $currentElementId, + 'lastElementId' => $lastElementId, + ]); + if ($currentElementId >= $lastElementId) { + $isStop = true; + } + } + } + + /** + * Get first element id in filtered result ordered by id asc + * + * + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @todo Кандидат на вынос + */ + private function getFirstElementId(string $apiMethod, array $filter, array $select): ?int + { + $this->log->debug('FilterWithoutBatchWithoutCountOrder.getFirstElementId.start', [ + 'apiMethod' => $apiMethod, + 'filter' => $filter, + 'select' => $select, + ]); + + $response = $this->core->call( + $apiMethod, + [ + 'order' => ['ID' => 'ASC'], + 'filter' => $filter, + 'select' => $select, + 'start' => 0, + ] + ); + + $elementId = $response->getResponseData()->getResult()[0]['ID']; + + $this->log->debug('FilterWithoutBatchWithoutCountOrder.getFirstElementId.finish', [ + 'elementId' => $elementId, + ]); + + return $elementId === null ? null : (int)$elementId; + } + + /** + * Get first element id in filtered result ordered by id asc + * + * + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @todo Кандидат на вынос + */ + private function getLastElementId(string $apiMethod, array $filter, array $select): ?int + { + $this->log->debug('FilterWithoutBatchWithoutCountOrder.getLastElementId.start', [ + 'apiMethod' => $apiMethod, + 'filter' => $filter, + 'select' => $select, + ]); + + $response = $this->core->call( + $apiMethod, + [ + 'order' => ['ID' => 'DESC'], + 'filter' => $filter, + 'select' => $select, + 'start' => 0, + ] + ); + + $elementId = $response->getResponseData()->getResult()[0]['ID']; + + $this->log->debug('FilterWithoutBatchWithoutCountOrder.getLastElementId.finish', [ + 'elementId' => $elementId, + ]); + + return $elementId === null ? null : (int)$elementId; + } +} \ No newline at end of file diff --git a/src/Core/Commands/Command.php b/src/Core/Commands/Command.php new file mode 100644 index 00000000..96139aa4 --- /dev/null +++ b/src/Core/Commands/Command.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Commands; + +use Symfony\Component\Uid\Uuid; + +class Command +{ + public function __construct( + private readonly string $apiMethod, + private readonly array $parameters, + private ?string $id = null) + { + if ($id === null) { + $this->id = (Uuid::v7())->toRfc4122(); + } + } + + public function getApiMethod(): string + { + return $this->apiMethod; + } + + public function getParameters(): array + { + return $this->parameters; + } + + public function getId(): string + { + return $this->id; + } +} diff --git a/src/Core/Commands/CommandCollection.php b/src/Core/Commands/CommandCollection.php new file mode 100644 index 00000000..17f2a7b9 --- /dev/null +++ b/src/Core/Commands/CommandCollection.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Commands; + +use SplObjectStorage; + +/** + * Class CommandCollection + * + * @package Bitrix24\SDK\Core\Commands + * + * @method attach(Command $command) + * @method Command current() + */ +class CommandCollection extends SplObjectStorage +{ +} \ No newline at end of file diff --git a/src/Core/Contracts/AddedItemIdResultInterface.php b/src/Core/Contracts/AddedItemIdResultInterface.php new file mode 100644 index 00000000..41808b4a --- /dev/null +++ b/src/Core/Contracts/AddedItemIdResultInterface.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Contracts; + +interface AddedItemIdResultInterface +{ + /** + * added entity id + */ + public function getId(): int; +} \ No newline at end of file diff --git a/src/Core/Contracts/ApiClientInterface.php b/src/Core/Contracts/ApiClientInterface.php new file mode 100644 index 00000000..748bbfb6 --- /dev/null +++ b/src/Core/Contracts/ApiClientInterface.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Contracts; + +use Bitrix24\SDK\Core\Credentials\Credentials; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Response\DTO\RenewedAuthToken; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; + +interface ApiClientInterface +{ + /** + * @throws TransportExceptionInterface + * @throws InvalidArgumentException + */ + public function getResponse(string $apiMethod, array $parameters = []): ResponseInterface; + + /** + * @throws InvalidArgumentException + * @throws TransportExceptionInterface + */ + public function getNewAuthToken(): RenewedAuthToken; + + public function getCredentials(): Credentials; +} \ No newline at end of file diff --git a/src/Core/Contracts/BatchOperationsInterface.php b/src/Core/Contracts/BatchOperationsInterface.php new file mode 100644 index 00000000..e79b415c --- /dev/null +++ b/src/Core/Contracts/BatchOperationsInterface.php @@ -0,0 +1,90 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Contracts; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Response\DTO\ResponseData; +use Generator; + +/** + * Interface BatchOperationsInterface + * + * @package Bitrix24\SDK\Core\Contracts + */ +interface BatchOperationsInterface +{ + /** + * Batch wrapper for *.list methods without counting elements on every api-call + * + * @param array $order + * @param array $filter + * @param array $select + * @return Generator + * @throws BaseException + */ + public function getTraversableList( + string $apiMethod, + array $order, + array $filter, + array $select, + ?int $limit = null, + ?array $additionalParameters = null + ): Generator; + + /** + * Batch wrapper for *.list methods with counting elements on every api-call + * + * ⚠️ Call this wrapper is more expensive than getTraversableList method, use this method carefully + * + * + * @throws BaseException + */ + public function getTraversableListWithCount( + string $apiMethod, + array $order, + array $filter, + array $select, + ?int $limit = null + ): Generator; + + /** + * Add entity items with batch call + * + * @param array $entityItems + * + * @return Generator|ResponseData[] + * @throws BaseException + */ + public function addEntityItems(string $apiMethod, array $entityItems): Generator; + + /** + * Delete entity items with batch call + * + * @param array $entityItemId + * + * @return Generator|ResponseData[] + * @throws BaseException + */ + public function deleteEntityItems(string $apiMethod, array $entityItemId): Generator; + + /** + * Update entity items with batch call + * + * @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/BulkItemsReaderInterface.php b/src/Core/Contracts/BulkItemsReaderInterface.php new file mode 100644 index 00000000..c9d8145d --- /dev/null +++ b/src/Core/Contracts/BulkItemsReaderInterface.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Contracts; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Generator; + +interface BulkItemsReaderInterface +{ + /** + * Wrapper for *.list methods for optimized bulk items read + * + * This reader used performance optimized read strategy selected by integrations tests + * + * @param string $apiMethod *.list method + * @param array $order elements order + * @param array $filter elements filter + * @param array $select select element fields + * @param int|null $limit limit elements or read all elements + * + * @throws BaseException + */ + public function getTraversableList(string $apiMethod, array $order, array $filter, array $select, ?int $limit = null): Generator; +} \ No newline at end of file diff --git a/src/Core/Contracts/CoreInterface.php b/src/Core/Contracts/CoreInterface.php new file mode 100644 index 00000000..d3d232d0 --- /dev/null +++ b/src/Core/Contracts/CoreInterface.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Contracts; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Response\Response; + +/** + * Interface CoreInterface + * + * @package Bitrix24\SDK\Core\Contracts + */ +interface CoreInterface +{ + /** + * @throws BaseException + * @throws TransportException + */ + public function call(string $apiMethod, array $parameters = []): Response; + + public function getApiClient(): ApiClientInterface; +} \ No newline at end of file diff --git a/src/Core/Contracts/DeletedItemResultInterface.php b/src/Core/Contracts/DeletedItemResultInterface.php new file mode 100644 index 00000000..868f541e --- /dev/null +++ b/src/Core/Contracts/DeletedItemResultInterface.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Contracts; + +interface DeletedItemResultInterface +{ + /** + * Success deletion flag + */ + public function isSuccess(): bool; +} \ 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..7dc006c2 --- /dev/null +++ b/src/Core/Contracts/UpdatedItemResultInterface.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Contracts; + +interface UpdatedItemResultInterface +{ + /** + * Success update flag + */ + public function isSuccess(): bool; +} \ No newline at end of file diff --git a/src/Core/Core.php b/src/Core/Core.php new file mode 100644 index 00000000..345b61e1 --- /dev/null +++ b/src/Core/Core.php @@ -0,0 +1,219 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core; + +use Bitrix24\SDK\Core\Commands\Command; +use Bitrix24\SDK\Core\Contracts\ApiClientInterface; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Exceptions\AuthForbiddenException; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\MethodConfirmWaitingException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Response\Response; +use Bitrix24\SDK\Events\AuthTokenRenewedEvent; +use Bitrix24\SDK\Events\PortalDomainUrlChangedEvent; +use Fig\Http\Message\StatusCodeInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\HttpClient\Exception\JsonException; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; + +class Core implements CoreInterface +{ + public function __construct( + protected ApiClientInterface $apiClient, + protected ApiLevelErrorHandler $apiLevelErrorHandler, + protected EventDispatcherInterface $eventDispatcher, + protected LoggerInterface $logger) + { + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function call(string $apiMethod, array $parameters = []): Response + { + $this->logger->debug( + 'call.start', + [ + 'method' => $apiMethod, + 'parameters' => $parameters, + ] + ); + + $response = null; + try { + // make async request + $apiCallResponse = $this->apiClient->getResponse($apiMethod, $parameters); + $this->logger->debug( + 'call.responseInfo', + [ + 'httpStatus' => $apiCallResponse->getStatusCode(), + ] + ); + switch ($apiCallResponse->getStatusCode()) { + case StatusCodeInterface::STATUS_OK: + //todo check with empty response size from server + $response = new Response($apiCallResponse, new Command($apiMethod, $parameters), $this->apiLevelErrorHandler, $this->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_BAD_REQUEST: + $body = $apiCallResponse->toArray(false); + $this->logger->notice( + 'bad request', + [ + 'rawResponse' => $body, + ] + ); + $this->apiLevelErrorHandler->handle($body); + break; + case StatusCodeInterface::STATUS_UNAUTHORIZED: + $body = $apiCallResponse->toArray(false); + $this->logger->debug( + 'UNAUTHORIZED request', + [ + 'rawResponse' => $body, + ] + ); + + switch (strtolower((string)$body['error'])) { + case 'expired_token': + // renew access token + $renewedToken = $this->apiClient->getNewAuthToken(); + $this->logger->debug( + 'access token renewed', + [ + 'newAccessToken' => $renewedToken->authToken->getAccessToken(), + 'newRefreshToken' => $renewedToken->authToken->getRefreshToken(), + 'newExpires' => $renewedToken->authToken->getExpires(), + 'appStatus' => $renewedToken->applicationStatus->getStatusCode(), + ] + ); + $this->apiClient->getCredentials()->setAuthToken($renewedToken->authToken); + + // repeat api-call + $response = $this->call($apiMethod, $parameters); + $this->logger->debug( + 'api call repeated', + [ + 'repeatedApiMethod' => $apiMethod, + 'httpStatusCode' => $response->getHttpResponse()->getStatusCode(), + ] + ); + + // dispatch event + $this->eventDispatcher->dispatch(new AuthTokenRenewedEvent($renewedToken)); + break; + case 'method_confirm_waiting': + throw new MethodConfirmWaitingException( + $apiMethod, + sprintf('api call method «%s» revoked, waiting confirm from portal administrator', $apiMethod)); + default: + throw new BaseException('UNAUTHORIZED request error'); + } + + break; + case StatusCodeInterface::STATUS_FORBIDDEN: + $body = $apiCallResponse->toArray(false); + $this->logger->warning( + 'bitrix24 portal authorisation forbidden', + [ + 'apiMethod' => $apiMethod, + 'b24DomainUrl' => $this->apiClient->getCredentials()->getDomainUrl(), + 'rawResponse' => $body, + ] + ); + $this->apiLevelErrorHandler->handle($body); + break; + case StatusCodeInterface::STATUS_SERVICE_UNAVAILABLE: + $body = $apiCallResponse->toArray(false); + $this->logger->notice( + 'bitrix24 portal unavailable', + [ + 'rawResponse' => $body, + ] + ); + $this->apiLevelErrorHandler->handle($body); + break; + default: + $body = $apiCallResponse->toArray(false); + $this->logger->notice( + 'unhandled server status', + [ + 'httpStatus' => $apiCallResponse->getStatusCode(), + 'rawResponse' => $body, + ] + ); + $this->apiLevelErrorHandler->handle($body); + break; + } + } catch (TransportExceptionInterface|JsonException $exception) { + // catch symfony http client transport exception + $this->logger->error( + 'call.transportException', + [ + 'trace' => $exception->getTrace(), + 'message' => $exception->getMessage(), + ] + ); + throw new TransportException(sprintf('transport error - %s, type %s', $exception->getMessage(), $exception::class), $exception->getCode(), $exception); + } catch (BaseException $exception) { + // rethrow known bitrix24 php sdk exception + throw $exception; + } catch (\Throwable $exception) { + $this->logger->error( + 'call.unknownException', + [ + 'message' => $exception->getMessage(), + 'class' => $exception::class, + 'trace' => $exception->getTrace(), + ] + ); + throw new BaseException(sprintf('unknown error - %s', $exception->getMessage()), $exception->getCode(), $exception); + } + + $this->logger->debug('call.finish'); + + return $response; + } + + public function getApiClient(): ApiClientInterface + { + return $this->apiClient; + } +} \ No newline at end of file diff --git a/src/Core/CoreBuilder.php b/src/Core/CoreBuilder.php new file mode 100644 index 00000000..a83eeac1 --- /dev/null +++ b/src/Core/CoreBuilder.php @@ -0,0 +1,136 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core; + +use Bitrix24\SDK\Core\Contracts\ApiClientInterface; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Credentials; +use Bitrix24\SDK\Core\Credentials\WebhookUrl; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Infrastructure\HttpClient\RequestId\DefaultRequestIdGenerator; +use Bitrix24\SDK\Infrastructure\HttpClient\RequestId\RequestIdGeneratorInterface; +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\HttpClient\HttpClient; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * Class CoreBuilder + * + * @package Bitrix24\SDK\Core + */ +class CoreBuilder +{ + private ?ApiClientInterface $apiClient = null; + + private HttpClientInterface $httpClient; + + private EventDispatcherInterface $eventDispatcher; + + private LoggerInterface $logger; + + private ?Credentials $credentials = null; + + private readonly ApiLevelErrorHandler $apiLevelErrorHandler; + + private RequestIdGeneratorInterface $requestIdGenerator; + + /** + * CoreBuilder constructor. + */ + public function __construct() + { + $this->logger = new NullLogger(); + $this->eventDispatcher = new EventDispatcher(); + $this->httpClient = HttpClient::create( + [ + 'http_version' => '2.0', + 'timeout' => 120, + ] + ); + $this->apiLevelErrorHandler = new ApiLevelErrorHandler($this->logger); + $this->requestIdGenerator = new DefaultRequestIdGenerator(); + } + + public function withRequestIdGenerator(RequestIdGeneratorInterface $requestIdGenerator): void + { + $this->requestIdGenerator = $requestIdGenerator; + } + + /** + * @return $this + */ + public function withCredentials(Credentials $credentials): self + { + $this->credentials = $credentials; + + return $this; + } + + public function withApiClient(ApiClientInterface $apiClient): self + { + $this->apiClient = $apiClient; + + return $this; + } + + public function withHttpClient(HttpClientInterface $httpClient):self + { + $this->httpClient = $httpClient; + + return $this; + } + + public function withLogger(LoggerInterface $logger): self + { + $this->logger = $logger; + + return $this; + } + + public function withEventDispatcher(EventDispatcherInterface $eventDispatcher): self + { + $this->eventDispatcher = $eventDispatcher; + + return $this; + } + + /** + * @throws InvalidArgumentException + */ + public function build(): CoreInterface + { + if (!$this->credentials instanceof \Bitrix24\SDK\Core\Credentials\Credentials) { + throw new InvalidArgumentException('you must set credentials before call method build'); + } + + if (!$this->apiClient instanceof \Bitrix24\SDK\Core\Contracts\ApiClientInterface) { + $this->apiClient = new ApiClient( + $this->credentials, + $this->httpClient, + $this->requestIdGenerator, + $this->logger + ); + } + + return new Core( + $this->apiClient, + $this->apiLevelErrorHandler, + $this->eventDispatcher, + $this->logger + ); + } +} \ No newline at end of file diff --git a/src/Core/Credentials/ApplicationProfile.php b/src/Core/Credentials/ApplicationProfile.php new file mode 100644 index 00000000..f8b0a39f --- /dev/null +++ b/src/Core/Credentials/ApplicationProfile.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Credentials; + +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; + +/** + * Class ApplicationProfile + * + * @package Bitrix24\SDK\Core\Credentials + */ +class ApplicationProfile +{ + 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'; + + /** + * ApplicationProfile constructor. + */ + public function __construct(private readonly string $clientId, private readonly string $clientSecret, private readonly Scope $scope) + { + } + + public function getClientId(): string + { + return $this->clientId; + } + + public function getClientSecret(): string + { + return $this->clientSecret; + } + + 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(',', (string) $appProfile[self::BITRIX24_PHP_SDK_APPLICATION_SCOPE]))), + ); + } +} \ No newline at end of file diff --git a/src/Core/Credentials/AuthToken.php b/src/Core/Credentials/AuthToken.php new file mode 100644 index 00000000..407cb50e --- /dev/null +++ b/src/Core/Credentials/AuthToken.php @@ -0,0 +1,110 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Credentials; + +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Symfony\Component\HttpFoundation; + +class AuthToken +{ + public function __construct( + protected string $accessToken, + protected ?string $refreshToken, + protected int $expires, + protected ?int $expiresIn = null) + { + } + + /** + * Is this one-off token from event + * + * One-off tokens do not have refresh token field + */ + public function isOneOff(): bool + { + return $this->refreshToken === null; + } + + public function getAccessToken(): string + { + return $this->accessToken; + } + + public function getRefreshToken(): ?string + { + return $this->refreshToken; + } + + public function getExpires(): int + { + return $this->expires; + } + + public function hasExpired(): bool + { + return $this->getExpires() <= time(); + } + + + public static function initFromArray(array $request): self + { + return new self( + (string)$request['access_token'], + (string)$request['refresh_token'], + (int)$request['expires'] + ); + } + + public static function initFromWorkflowRequest(HttpFoundation\Request $request): self + { + $requestFields = $request->request->all(); + return self::initFromArray($requestFields['auth']); + } + + public static function initFromEventRequest(HttpFoundation\Request $request): self + { + $requestFields = $request->request->all(); + return new self( + $requestFields['auth']['access_token'], + null, + (int)$requestFields['auth']['expires'], + (int)$requestFields['auth']['expires_in'], + ); + } + + /** + * @throws InvalidArgumentException + */ + public static function initFromPlacementRequest(HttpFoundation\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/Credentials.php b/src/Core/Credentials/Credentials.php new file mode 100644 index 00000000..5a17e3d2 --- /dev/null +++ b/src/Core/Credentials/Credentials.php @@ -0,0 +1,137 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Credentials; + +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Application\Requests\Placement\PlacementRequest; + +class Credentials +{ + protected ?string $domainUrl = null; + + /** + * @throws InvalidArgumentException + */ + public function __construct( + protected ?WebhookUrl $webhookUrl, + protected ?AuthToken $authToken, + protected ?ApplicationProfile $applicationProfile, + ?string $domainUrl + ) + { + if ($domainUrl !== null) { + $this->setDomainUrl($domainUrl); + } + + if (!$this->authToken instanceof AuthToken && !$this->webhookUrl instanceof WebhookUrl) { + throw new InvalidArgumentException('you must set on of auth type: webhook or OAuth 2.0'); + } + + if ($this->authToken instanceof AuthToken && $this->domainUrl === null) { + throw new InvalidArgumentException('for oauth type you must set domain url'); + } + } + + public function setAuthToken(AuthToken $authToken): void + { + $this->authToken = $authToken; + } + + /** + * Set domain url + * + * + * @throws 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; + } + + public function isWebhookContext(): bool + { + return $this->webhookUrl instanceof WebhookUrl && !$this->authToken instanceof AuthToken; + } + + public function getApplicationProfile(): ?ApplicationProfile + { + return $this->applicationProfile; + } + + public function getDomainUrl(): string + { + $arUrl = $this->getWebhookUrl() instanceof WebhookUrl ? parse_url($this->getWebhookUrl()->getUrl()) : parse_url((string)$this->domainUrl); + + return sprintf('%s://%s', $arUrl['scheme'], $arUrl['host']); + } + + public function getWebhookUrl(): ?WebhookUrl + { + return $this->webhookUrl; + } + + public function getAuthToken(): ?AuthToken + { + return $this->authToken; + } + + /** + * @throws InvalidArgumentException + */ + public static function createFromWebhook(WebhookUrl $webhookUrl): self + { + return new self( + $webhookUrl, + null, + null, + null + ); + } + + /** + * + * @throws InvalidArgumentException + */ + public static function createFromOAuth(AuthToken $authToken, ApplicationProfile $applicationProfile, string $domainUrl): self + { + return new self( + null, + $authToken, + $applicationProfile, + $domainUrl + ); + } + + /** + * + * @throws 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/Endpoints.php b/src/Core/Credentials/Endpoints.php new file mode 100644 index 00000000..a5dcb86f --- /dev/null +++ b/src/Core/Credentials/Endpoints.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Core\Credentials; + +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; + +readonly class Endpoints +{ + /** + * @throws InvalidArgumentException + */ + public function __construct( + /** + * @phpstan-param non-empty-string $authServerUrl + */ + public string $authServerUrl, + /** + * @phpstan-param non-empty-string $clientUrl + */ + public string $clientUrl, + ) + { + if (filter_var($authServerUrl, FILTER_VALIDATE_URL) === false) { + throw new InvalidArgumentException(sprintf('authServer endpoint URL «%s» is invalid', $authServerUrl)); + } + + if (filter_var($clientUrl, FILTER_VALIDATE_URL) === false) { + throw new InvalidArgumentException(sprintf('client endpoint URL «%s» is invalid', $clientUrl)); + } + } + + /** + * @throws InvalidArgumentException + */ + public static function initFromArray(array $auth): self + { + return new self( + $auth['server_endpoint'], + $auth['client_endpoint'], + ); + } +} \ No newline at end of file diff --git a/src/Core/Credentials/Scope.php b/src/Core/Credentials/Scope.php new file mode 100644 index 00000000..1fabfac8 --- /dev/null +++ b/src/Core/Credentials/Scope.php @@ -0,0 +1,127 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Credentials; + +use Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException; + +class Scope +{ + /** + * @var string[] + */ + protected array $availableScope = [ + 'ai_admin', + 'appform', + 'baas', + 'bizproc', + 'biconnector', + 'calendar', + 'calendarmobile', + 'catalogmobile', + 'call', + 'cashbox', + 'catalog', + 'configuration.import', + 'contact_center', + 'crm', + 'delivery', + 'department', + 'disk', + 'documentgenerator', + 'entity', + 'faceid', + 'forum', + 'iblock', + 'im', + 'imbot', + 'imopenlines', + 'im.import', + 'imconnector', + 'intranet', + 'landing', + 'landing_cloud', + 'lists', + 'log', + 'mailservice', + 'messageservice', + 'mobile', + 'notifications', + 'pay_system', + 'placement', + 'pull', + 'pull_channel', + 'rating', + 'rpa', + 'sale', + 'salescenter', + 'smile', + 'socialnetwork', + 'sonet_group', + 'task', + 'tasks', + 'tasks_extended', + 'tasksmobile', + 'telephony', + 'timeman', + 'user', + 'user_basic', + 'user_brief', + 'user.userfield', + 'userconsent', + 'userfieldconfig', + ]; + + protected array $currentScope = []; + + /** + * Scope constructor. + * + * + * @throws UnknownScopeCodeException + */ + public function __construct(array $scope = []) + { + $scope = array_unique(array_map(strtolower(...), $scope)); + sort($scope); + if (count($scope) === 1 && $scope[0] === '') { + $scope = []; + } else { + foreach ($scope as $item) { + if (!in_array($item, $this->availableScope, true)) { + throw new UnknownScopeCodeException(sprintf('unknown application scope code - %s', $item)); + } + } + } + + $this->currentScope = $scope; + } + + public function equal(self $scope): bool + { + return $this->currentScope === $scope->getScopeCodes(); + } + + public function getScopeCodes(): array + { + return $this->currentScope; + } + + /** + * @throws UnknownScopeCodeException + */ + public static function initFromString(string $scope): self + { + return new self(str_replace(' ', '', explode(',', $scope))); + } +} \ No newline at end of file diff --git a/src/Core/Credentials/WebhookUrl.php b/src/Core/Credentials/WebhookUrl.php new file mode 100644 index 00000000..f45d513e --- /dev/null +++ b/src/Core/Credentials/WebhookUrl.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Credentials; + +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; + +/** + * Class WebhookUrl + * + * @package Bitrix24\SDK\Core\Credentials + */ +class WebhookUrl +{ + protected string $url; + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public function __construct(string $webhookUrl) + { + if (filter_var($webhookUrl, FILTER_VALIDATE_URL) === false) { + throw new InvalidArgumentException(sprintf('webhook URL %s is invalid', $webhookUrl)); + } + + $this->url = $webhookUrl; + } + + public function getUrl(): string + { + return $this->url; + } +} \ No newline at end of file diff --git a/src/Core/Exceptions/AuthForbiddenException.php b/src/Core/Exceptions/AuthForbiddenException.php new file mode 100644 index 00000000..77bdb342 --- /dev/null +++ b/src/Core/Exceptions/AuthForbiddenException.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Exceptions; + +class AuthForbiddenException extends BaseException +{ +} \ No newline at end of file diff --git a/src/Core/Exceptions/BaseException.php b/src/Core/Exceptions/BaseException.php new file mode 100644 index 00000000..a0a94c2e --- /dev/null +++ b/src/Core/Exceptions/BaseException.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Exceptions; + +/** + * Class BaseException + * + * @package Bitrix24\SDK\Core\Exceptions + */ +class BaseException extends \Exception +{ +} \ No newline at end of file diff --git a/src/Core/Exceptions/FileNotFoundException.php b/src/Core/Exceptions/FileNotFoundException.php new file mode 100644 index 00000000..1f592d6e --- /dev/null +++ b/src/Core/Exceptions/FileNotFoundException.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Exceptions; + +class FileNotFoundException extends BaseException +{ +} \ No newline at end of file diff --git a/src/Core/Exceptions/ImmutableResultViolationException.php b/src/Core/Exceptions/ImmutableResultViolationException.php new file mode 100644 index 00000000..78f43671 --- /dev/null +++ b/src/Core/Exceptions/ImmutableResultViolationException.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Exceptions; + +/** + * Class ImmutableResultViolationException + * + * @package Bitrix24\SDK\Core\Exceptions + */ +class ImmutableResultViolationException extends BaseException +{ +} \ No newline at end of file diff --git a/src/Core/Exceptions/InvalidArgumentException.php b/src/Core/Exceptions/InvalidArgumentException.php new file mode 100644 index 00000000..d891da52 --- /dev/null +++ b/src/Core/Exceptions/InvalidArgumentException.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Exceptions; + +/** + * Class InvalidArgumentException + * + * @package Bitrix24\SDK\Core\Exceptions + */ +class InvalidArgumentException extends BaseException +{ +} \ No newline at end of file diff --git a/src/Core/Exceptions/MethodConfirmWaitingException.php b/src/Core/Exceptions/MethodConfirmWaitingException.php new file mode 100644 index 00000000..8018452a --- /dev/null +++ b/src/Core/Exceptions/MethodConfirmWaitingException.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Exceptions; + +use Throwable; + +class MethodConfirmWaitingException extends BaseException +{ + public function __construct(public readonly string $methodName, string $message, int $code = 0, ?Throwable $throwable = null) + { + parent::__construct($message, $code, $throwable); + } +} \ No newline at end of file diff --git a/src/Core/Exceptions/MethodNotFoundException.php b/src/Core/Exceptions/MethodNotFoundException.php new file mode 100644 index 00000000..858b0ed7 --- /dev/null +++ b/src/Core/Exceptions/MethodNotFoundException.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Exceptions; + +/** + * Class MethodNotFoundException + * + * @package Bitrix24\SDK\Core\Exceptions + */ +class MethodNotFoundException extends BaseException +{ +} \ No newline at end of file diff --git a/src/Core/Exceptions/OperationTimeLimitExceededException.php b/src/Core/Exceptions/OperationTimeLimitExceededException.php new file mode 100644 index 00000000..2a1ef6f8 --- /dev/null +++ b/src/Core/Exceptions/OperationTimeLimitExceededException.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Exceptions; + +/** + * Class OperationTimeLimitExceededException + * + * @package Bitrix24\SDK\Core\Exceptions + */ +class OperationTimeLimitExceededException extends BaseException +{ +} \ No newline at end of file diff --git a/src/Core/Exceptions/QueryLimitExceededException.php b/src/Core/Exceptions/QueryLimitExceededException.php new file mode 100644 index 00000000..9ba9b4c8 --- /dev/null +++ b/src/Core/Exceptions/QueryLimitExceededException.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Exceptions; + +/** + * Class QueryLimitExceededException + * + * @package Bitrix24\SDK\Core\Exceptions + */ +class QueryLimitExceededException extends BaseException +{ +} \ No newline at end of file diff --git a/src/Core/Exceptions/TransportException.php b/src/Core/Exceptions/TransportException.php new file mode 100644 index 00000000..4701cbaa --- /dev/null +++ b/src/Core/Exceptions/TransportException.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Exceptions; + +/** + * When any error happens at the transport level. + * + * Class TransportException + * + * @package Bitrix24\SDK\Core\Exceptions + */ +class TransportException extends BaseException +{ +} \ No newline at end of file diff --git a/src/Core/Exceptions/UnknownScopeCodeException.php b/src/Core/Exceptions/UnknownScopeCodeException.php new file mode 100644 index 00000000..e6af1e15 --- /dev/null +++ b/src/Core/Exceptions/UnknownScopeCodeException.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Exceptions; + +/** + * Class UnknownScopeCodeException + * + * @package Bitrix24\SDK\Core\Exceptions + */ +class UnknownScopeCodeException extends InvalidArgumentException +{ +} \ No newline at end of file diff --git a/src/Core/Exceptions/UserNotFoundOrIsNotActiveException.php b/src/Core/Exceptions/UserNotFoundOrIsNotActiveException.php new file mode 100644 index 00000000..567ddcbd --- /dev/null +++ b/src/Core/Exceptions/UserNotFoundOrIsNotActiveException.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Exceptions; + +class UserNotFoundOrIsNotActiveException extends BaseException +{ +} \ No newline at end of file diff --git a/src/Core/Exceptions/WrongAuthTypeException.php b/src/Core/Exceptions/WrongAuthTypeException.php new file mode 100644 index 00000000..72bad354 --- /dev/null +++ b/src/Core/Exceptions/WrongAuthTypeException.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Exceptions; +class WrongAuthTypeException extends BaseException +{ +} \ No newline at end of file diff --git a/src/Core/Fields/FieldsFilter.php b/src/Core/Fields/FieldsFilter.php new file mode 100644 index 00000000..be27dba5 --- /dev/null +++ b/src/Core/Fields/FieldsFilter.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Fields; + +class FieldsFilter +{ + public function filterSystemFields(array $fieldCodes): array + { + $res = []; + foreach ($fieldCodes as $fieldCode) { + if (!str_starts_with((string) $fieldCode, 'UF_CRM_')) { + $res[] = $fieldCode; + } + } + + return $res; + } +} diff --git a/src/Core/Response/DTO/Pagination.php b/src/Core/Response/DTO/Pagination.php new file mode 100644 index 00000000..8d158ea8 --- /dev/null +++ b/src/Core/Response/DTO/Pagination.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Response\DTO; + +readonly class Pagination +{ + public function __construct( + private ?int $nextItem = null, + private ?int $total = null) + { + } + + public function getNextItem(): ?int + { + return $this->nextItem; + } + + public function getTotal(): ?int + { + return $this->total; + } +} \ No newline at end of file diff --git a/src/Core/Response/DTO/RenewedAuthToken.php b/src/Core/Response/DTO/RenewedAuthToken.php new file mode 100644 index 00000000..8b4ed1a6 --- /dev/null +++ b/src/Core/Response/DTO/RenewedAuthToken.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Response\DTO; + +use Bitrix24\SDK\Application\ApplicationStatus; +use Bitrix24\SDK\Core\Credentials\AuthToken; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; + +readonly class RenewedAuthToken +{ + /** + * @param non-empty-string $memberId + * @param non-empty-string $clientEndpoint + * @param non-empty-string $serverEndpoint + * @param non-empty-string $domain + */ + public function __construct( + public AuthToken $authToken, + public string $memberId, + public string $clientEndpoint, + public string $serverEndpoint, + public ApplicationStatus $applicationStatus, + public string $domain) + { + } + + /** + * @throws InvalidArgumentException + */ + public static function initFromArray(array $response): self + { + return new self( + AuthToken::initFromArray($response), + (string)$response['member_id'], + (string)$response['client_endpoint'], + (string)$response['server_endpoint'], + ApplicationStatus::initFromString((string)$response['status']), + (string)$response['domain'] + ); + } +} \ No newline at end of file diff --git a/src/Core/Response/DTO/ResponseData.php b/src/Core/Response/DTO/ResponseData.php new file mode 100644 index 00000000..cbcec359 --- /dev/null +++ b/src/Core/Response/DTO/ResponseData.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Response\DTO; + +class ResponseData +{ + /** + * ResponseData constructor. + */ + public function __construct( + protected array $result, + readonly protected Time $time, + readonly protected Pagination $pagination) + { + } + + public function getPagination(): Pagination + { + return $this->pagination; + } + + public function getTime(): Time + { + return $this->time; + } + + public function getResult(): 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 new file mode 100644 index 00000000..d87f3814 --- /dev/null +++ b/src/Core/Response/DTO/Time.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Response\DTO; + +use Carbon\CarbonImmutable; +use Exception; + +readonly class Time +{ + public function __construct( + public float $start, + public float $finish, + public float $duration, + public float $processing, + /** + * @see https://training.bitrix24.com/rest_help/rest_sum/operating.php + */ + public float $operating, + public CarbonImmutable $dateStart, + public CarbonImmutable $dateFinish, + /** + * @see https://training.bitrix24.com/rest_help/rest_sum/operating.php + */ + public ?int $operatingResetAt + ) + { + } + + /** + * @throws Exception + */ + public static function initFromResponse(array $response): self + { + return new self( + (float)$response['start'], + (float)$response['finish'], + (float)$response['duration'], + (float)$response['processing'], + array_key_exists('operating', $response) ? (float)$response['operating'] : 0, + new CarbonImmutable($response['date_start']), + new CarbonImmutable($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 new file mode 100644 index 00000000..1f0efb2c --- /dev/null +++ b/src/Core/Response/Response.php @@ -0,0 +1,116 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Response; + +use Bitrix24\SDK\Core\ApiLevelErrorHandler; +use Bitrix24\SDK\Core\Commands\Command; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Response\DTO; +use Bitrix24\SDK\Infrastructure\HttpClient\TransportLayer\NetworkTimingsParser; +use Bitrix24\SDK\Infrastructure\HttpClient\TransportLayer\ResponseInfoParser; +use Psr\Log\LoggerInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; +use Throwable; + +class Response +{ + protected ?DTO\ResponseData $responseData = null; + + /** + * Response constructor. + */ + public function __construct( + protected ResponseInterface $httpResponse, + protected Command $apiCommand, + protected ApiLevelErrorHandler $apiLevelErrorHandler, + protected LoggerInterface $logger) + { + } + + public function getHttpResponse(): ResponseInterface + { + return $this->httpResponse; + } + + public function getApiCommand(): Command + { + return $this->apiCommand; + } + + /** + * @throws BaseException + */ + public function getResponseData(): DTO\ResponseData + { + $this->logger->debug('getResponseData.start'); + + if (!$this->responseData instanceof \Bitrix24\SDK\Core\Response\DTO\ResponseData) { + try { + $this->logger->debug('getResponseData.parseResponse.start'); + $responseResult = $this->httpResponse->toArray(true); + $this->logger->info('getResponseData.responseBody', [ + 'responseBody' => $responseResult, + ]); + + // try to handle api-level errors + $this->apiLevelErrorHandler->handle($responseResult); + + if (!is_array($responseResult['result'])) { + $responseResult['result'] = [$responseResult['result']]; + } + + $nextItem = null; + $total = null; + if (array_key_exists('next', $responseResult)) { + $nextItem = (int)$responseResult['next']; + } + + if (array_key_exists('total', $responseResult)) { + $total = (int)$responseResult['total']; + } + + $this->responseData = new DTO\ResponseData( + $responseResult['result'], + DTO\Time::initFromResponse($responseResult['time']), + new DTO\Pagination($nextItem, $total) + ); + $this->logger->debug('getResponseData.parseResponse.finish'); + } catch (Throwable $exception) { + $this->logger->error( + $exception->getMessage(), + [ + 'response' => $this->getHttpResponseContent(), + ] + ); + throw new BaseException(sprintf('api request error: %s', $exception->getMessage()), $exception->getCode(), $exception); + } + } + + $this->logger->debug('getResponseData.finish'); + + return $this->responseData; + } + + private function getHttpResponseContent(): ?string + { + $content = null; + try { + $content = $this->httpResponse->getContent(false); + } catch (Throwable $throwable) { + $this->logger->error($throwable->getMessage()); + } + + return $content; + } +} \ No newline at end of file diff --git a/src/Core/Result/AbstractItem.php b/src/Core/Result/AbstractItem.php new file mode 100644 index 00000000..7daec5f3 --- /dev/null +++ b/src/Core/Result/AbstractItem.php @@ -0,0 +1,90 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Result; + +use ArrayIterator; +use Bitrix24\SDK\Core\Exceptions\ImmutableResultViolationException; +use IteratorAggregate; +use Money\Currencies\ISOCurrencies; +use Money\Parser\DecimalMoneyParser; +use Traversable; + +/** + * Class AbstractItem + * + * @package Bitrix24\SDK\Core\Result + */ +abstract class AbstractItem implements IteratorAggregate +{ + protected DecimalMoneyParser $decimalMoneyParser; + + public function __construct(protected array $data) + { + $this->decimalMoneyParser = new DecimalMoneyParser(new ISOCurrencies()); + } + + /** + * @param int|string $offset + */ + public function __isset($offset): bool + { + return isset($this->data[$offset]); + } + + /** + * @param int|string $offset + * + * @return mixed + */ + public function __get($offset) + { + return $this->data[$offset] ?? null; + } + + /** + * @param int|string $offset + * + * @return void + * @throws ImmutableResultViolationException + * + */ + public function __set($offset, mixed $value) + { + throw new ImmutableResultViolationException(sprintf('Result is immutable, violation at offset %s', $offset)); + } + + /** + * @param int|string $offset + * + * @throws ImmutableResultViolationException + */ + public function __unset($offset) + { + throw new ImmutableResultViolationException(sprintf('Result is immutable, violation at offset %s', $offset)); + } + + /** + * {@inheritdoc} + */ + public function getIterator(): Traversable + { + return new ArrayIterator($this->data); + } + + + protected function isKeyExists(string $key): bool + { + return array_key_exists($key, $this->data); + } +} \ No newline at end of file diff --git a/src/Core/Result/AbstractResult.php b/src/Core/Result/AbstractResult.php new file mode 100644 index 00000000..a9c0171c --- /dev/null +++ b/src/Core/Result/AbstractResult.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Result; + +use Bitrix24\SDK\Core\Response\Response; + +/** + * Class AbstractResult + * + * @package Bitrix24\SDK\Core\Result + */ +abstract class AbstractResult +{ + /** + * AbstractResult constructor. + */ + public function __construct(protected Response $coreResponse) + { + } + + public function getCoreResponse(): Response + { + return $this->coreResponse; + } +} \ No newline at end of file diff --git a/src/Core/Result/AddedItemBatchResult.php b/src/Core/Result/AddedItemBatchResult.php new file mode 100644 index 00000000..0babf68b --- /dev/null +++ b/src/Core/Result/AddedItemBatchResult.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Result; + +use Bitrix24\SDK\Core\Contracts\AddedItemIdResultInterface; +use Bitrix24\SDK\Core\Response\DTO\ResponseData; + +class AddedItemBatchResult implements AddedItemIdResultInterface +{ + public function __construct(private readonly ResponseData $responseData) + { + } + + public function getResponseData(): ResponseData + { + return $this->responseData; + } + + public function getId(): int + { + 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 new file mode 100644 index 00000000..73ae94fa --- /dev/null +++ b/src/Core/Result/AddedItemResult.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Result; + +use Bitrix24\SDK\Core\Contracts\AddedItemIdResultInterface; +use Bitrix24\SDK\Core\Exceptions\BaseException; + +/** + * Class AddedItemResult + * + * @package Bitrix24\SDK\Core\Result + */ +class AddedItemResult extends AbstractResult implements AddedItemIdResultInterface +{ + /** + * @throws BaseException + */ + public function getId(): int + { + 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 new file mode 100644 index 00000000..6e17d9c6 --- /dev/null +++ b/src/Core/Result/DeletedItemBatchResult.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Result; + +use Bitrix24\SDK\Core\Contracts\DeletedItemResultInterface; +use Bitrix24\SDK\Core\Response\DTO\ResponseData; + +class DeletedItemBatchResult implements DeletedItemResultInterface +{ + public function __construct(private readonly ResponseData $responseData) + { + } + + public function getResponseData(): ResponseData + { + return $this->responseData; + } + + public function isSuccess(): bool + { + 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 new file mode 100644 index 00000000..76a9d49d --- /dev/null +++ b/src/Core/Result/DeletedItemResult.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Result; + +use Bitrix24\SDK\Core\Contracts\DeletedItemResultInterface; +use Bitrix24\SDK\Core\Exceptions\BaseException; + +/** + * Class DeletedItemResult + * + * @package Bitrix24\SDK\Core\Result + */ +class DeletedItemResult extends AbstractResult implements DeletedItemResultInterface +{ + /** + * @throws BaseException + */ + public function isSuccess(): bool + { + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Core/Result/EmptyResult.php b/src/Core/Result/EmptyResult.php new file mode 100644 index 00000000..7119a7cc --- /dev/null +++ b/src/Core/Result/EmptyResult.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Result; + +use Bitrix24\SDK\Core\Contracts\DeletedItemResultInterface; +use Bitrix24\SDK\Core\Exceptions\BaseException; + +class EmptyResult extends AbstractResult +{ +} \ No newline at end of file diff --git a/src/Core/Result/FieldsResult.php b/src/Core/Result/FieldsResult.php new file mode 100644 index 00000000..3b0799ea --- /dev/null +++ b/src/Core/Result/FieldsResult.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; + +/** + * Class FieldsResult + * + * @package Bitrix24\SDK\Core\Result + */ +class FieldsResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function getFieldsDescription(): array + { + 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..7456934c --- /dev/null +++ b/src/Core/Result/UpdatedItemBatchResult.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Result; + +use Bitrix24\SDK\Core\Contracts\UpdatedItemResultInterface; +use Bitrix24\SDK\Core\Response\DTO\ResponseData; + +class UpdatedItemBatchResult implements UpdatedItemResultInterface +{ + public function __construct(private readonly ResponseData $responseData) + { + } + + public function getResponseData(): ResponseData + { + return $this->responseData; + } + + 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 new file mode 100644 index 00000000..9656dddc --- /dev/null +++ b/src/Core/Result/UpdatedItemResult.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; + +/** + * Class UpdatedItemResult + * + * @package Bitrix24\SDK\Core\Result + */ +class UpdatedItemResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function isSuccess(): bool + { + return (bool)$this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Core/Result/UserInterfaceDialogCallResult.php b/src/Core/Result/UserInterfaceDialogCallResult.php new file mode 100644 index 00000000..a5a19c66 --- /dev/null +++ b/src/Core/Result/UserInterfaceDialogCallResult.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Core\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; + +class UserInterfaceDialogCallResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function isSuccess(): bool + { + 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 new file mode 100644 index 00000000..985b9ba7 --- /dev/null +++ b/src/Events/AuthTokenRenewedEvent.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Events; + +use Bitrix24\SDK\Core\Response\DTO\RenewedAuthToken; +use Symfony\Contracts\EventDispatcher\Event; + + +class AuthTokenRenewedEvent extends Event +{ + private RenewedAuthToken $renewedToken; + + /** + * AuthTokenRenewedEvent constructor. + * + * @param RenewedAuthToken $renewedToken + */ + public function __construct(RenewedAuthToken $renewedToken) + { + $this->renewedToken = $renewedToken; + } + + /** + * @return RenewedAuthToken + */ + public function getRenewedToken(): RenewedAuthToken + { + return $this->renewedToken; + } +} diff --git a/src/Events/PortalDomainUrlChangedEvent.php b/src/Events/PortalDomainUrlChangedEvent.php new file mode 100644 index 00000000..928b85d8 --- /dev/null +++ b/src/Events/PortalDomainUrlChangedEvent.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Events; + +use Symfony\Contracts\EventDispatcher\Event; + +class PortalDomainUrlChangedEvent extends Event +{ + private string $oldDomainUrlHost; + private string $newDomainUrlHost; + + /** + * @param string $oldDomainUrlHost + * @param string $newDomainUrlHost + */ + public function __construct(string $oldDomainUrlHost, string $newDomainUrlHost) + { + $this->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/Console/Commands/GenerateCoverageDocumentationCommand.php b/src/Infrastructure/Console/Commands/GenerateCoverageDocumentationCommand.php new file mode 100644 index 00000000..026be74e --- /dev/null +++ b/src/Infrastructure/Console/Commands/GenerateCoverageDocumentationCommand.php @@ -0,0 +1,245 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Infrastructure\Console\Commands; + +use Bitrix24\SDK\Attributes\Services\AttributesParser; +use Bitrix24\SDK\Services\ServiceBuilderFactory; +use InvalidArgumentException; +use Psr\Log\LoggerInterface; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Filesystem\Filesystem; +use Symfony\Component\Finder\Finder; +use Throwable; + +#[AsCommand( + name: 'b24:util:generate-coverage-documentation', + description: 'generate coverage documentation for all api commands', + hidden: false +)] +class GenerateCoverageDocumentationCommand extends Command +{ + private const WEBHOOK_URL = 'webhook'; + private const PUBLIC_REPO_URL = 'repository-url'; + private const TARGET_BRANCH = 'repository-branch'; + private const TARGET_FILE = 'file'; + + public function __construct( + private readonly AttributesParser $attributesParser, + private readonly ServiceBuilderFactory $serviceBuilderFactory, + private readonly Finder $finder, + private readonly Filesystem $filesystem, + private readonly LoggerInterface $logger) + { + // best practices recommend to call the parent constructor first and + // then set your own properties. That wouldn't work in this case + // because configure() needs the properties set in this constructor + parent::__construct(); + } + + protected function configure(): void + { + $this + ->setHelp('generate coverage report for all api commands based on actual methods list from api and api service attributes') + ->addOption( + self::WEBHOOK_URL, + null, + InputOption::VALUE_REQUIRED, + 'bitrix24 incoming webhook', + '' + ) + ->addOption( + self::PUBLIC_REPO_URL, + null, + InputOption::VALUE_REQUIRED, + 'public repository url', + '' + ) + ->addOption( + self::TARGET_BRANCH, + null, + InputOption::VALUE_REQUIRED, + 'target branch name', + '' + ) + ->addOption( + self::TARGET_FILE, + null, + InputOption::VALUE_REQUIRED, + 'file for generated documentation', + '' + ); + } + + private function loadAllServiceClasses(): void + { + $directory = 'src/Services'; + $this->finder->files()->in($directory)->name('*.php'); + foreach ($this->finder as $file) { + if ($file->isDir()) { + continue; + } + + $absoluteFilePath = $file->getRealPath(); + require_once $absoluteFilePath; + } + } + + /** + * @param non-empty-string $namespace + * @return array + */ + private function getAllSdkClassNames(string $namespace): array + { + $allClasses = get_declared_classes(); + return array_filter($allClasses, static function ($class) use ($namespace) { + return strncmp($class, $namespace, 12) === 0; + }); + } + + private function createTableInMarkdownFormat( + array $supportedInSdkMethods, + array $supportedInSdkBatchMethods, + string $publicRepoUrl, + string $publicRepoBranch + ): string + { + $tableHeader = <<`%s`
", + $method['sdk_class_name'] . '::' . $method['sdk_method_name']); + $batchMethodsHint .= sprintf("Return type: `%s`", $method['sdk_method_return_type_typhoon']); + } + $batchMethodsHint .= ""; + } + + $sdkMethodPublicUrl = sprintf('%s/%s/%s#L%s-L%s', + $publicRepoUrl, + $publicRepoBranch, + $apiMethod['sdk_method_file_name'], + $apiMethod['sdk_method_file_start_line'], + $apiMethod['sdk_method_file_end_line'], + ); + $sdkMethodReturnTypePublicUrl = sprintf('%s/%s/%s', + $publicRepoUrl, + $publicRepoBranch, + $apiMethod['sdk_return_type_file_name']); + + $table .= sprintf("\n|`%s`|[%s](%s)|%s|[`%s`](%s)
Return type
[`%s`](%s)%s|", + $apiMethod['sdk_scope'] === '' ? '–' : $apiMethod['sdk_scope'], + $apiMethod['name'], + $apiMethod['documentation_url'], + $apiMethod['description'], + $apiMethod['sdk_class_name'] . '::' . $apiMethod['sdk_method_name'], + $sdkMethodPublicUrl, + $apiMethod['sdk_return_type_class'], + $sdkMethodReturnTypePublicUrl, + $batchMethodsHint + ); + } + + return $table; + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + try { + $b24Webhook = (string)$input->getOption(self::WEBHOOK_URL); + if ($b24Webhook === '') { + throw new InvalidArgumentException('you must provide a webhook url in argument «webhook»'); + } + $publicRepoUrl = (string)$input->getOption(self::PUBLIC_REPO_URL); + if ($publicRepoUrl === '') { + throw new InvalidArgumentException('you must provide a public repository url in argument «repository-url»'); + } + $targetRepoBranch = (string)$input->getOption(self::TARGET_BRANCH); + if ($targetRepoBranch === '') { + throw new InvalidArgumentException('you must provide a target repository branch name in argument «repository-branch»'); + } + $targetFile = (string)$input->getOption(self::TARGET_FILE); + if ($targetFile === '') { + throw new InvalidArgumentException('you must provide a file to save generated documentation «file»'); + } + $this->logger->debug('GenerateCoverageDocumentationCommand.start', [ + 'b24Webhook' => $b24Webhook, + 'publicRepoUrl' => $publicRepoUrl, + 'targetRepoBranch' => $targetRepoBranch, + 'targetFile' => $targetFile + ]); + + $io->info('Generate api coverage report'); + // get all available api methods + $sb = $this->serviceBuilderFactory->initFromWebhook($b24Webhook); + $allApiMethods = $sb->getMainScope()->main()->getAvailableMethods()->getResponseData()->getResult(); + + // load and filter classes in namespace Bitrix24\SDK from folder src/Services + $this->loadAllServiceClasses(); + $sdkClassNames = $this->getAllSdkClassNames('Bitrix24\SDK'); + // get sdk root path, change magic number if move current file to another folder depth + $sdkBasePath = dirname(__FILE__, 5) . '/'; + + $supportedInSdkMethods = $this->attributesParser->getSupportedInSdkApiMethods($sdkClassNames, $sdkBasePath); + $supportedInSdkBatchMethods = $this->attributesParser->getSupportedInSdkBatchMethods($sdkClassNames); + + $allApiMethodsCnt = count($allApiMethods); + $supportedInSdkMethodsCnt = count($supportedInSdkMethods); + $supportedInSdkBatchMethodsCnt = count($supportedInSdkBatchMethods); + + // build coverage documentation in Markdown format + $mdTable = $this->createTableInMarkdownFormat( + $supportedInSdkMethods, + $supportedInSdkBatchMethods, + $publicRepoUrl, + $targetRepoBranch + ); + // save documentation to file + if ($this->filesystem->exists($targetFile)) { + $this->filesystem->remove($targetFile); + } + $this->filesystem->dumpFile($targetFile, $mdTable); + + $output->writeln([ + sprintf('Bitrix24 API-methods count: %d', $allApiMethodsCnt), + sprintf('Supported in bitrix24-php-sdk methods count: %d', $supportedInSdkMethodsCnt), + sprintf('Coverage percentage: %s%% 🚀', round(($supportedInSdkMethodsCnt * 100) / $allApiMethodsCnt, 2)), + '', + sprintf('Supported in bitrix24-php-sdk methods with batch wrapper count: %d', $supportedInSdkBatchMethodsCnt), + '' + ]); + + } catch (Throwable $exception) { + $io->error(sprintf('runtime error: %s', $exception->getMessage())); + $io->info($exception->getTraceAsString()); + + return self::INVALID; + } + return self::SUCCESS; + } +} \ No newline at end of file diff --git a/src/Infrastructure/Filesystem/Base64Encoder.php b/src/Infrastructure/Filesystem/Base64Encoder.php new file mode 100644 index 00000000..efa46705 --- /dev/null +++ b/src/Infrastructure/Filesystem/Base64Encoder.php @@ -0,0 +1,81 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Infrastructure\Filesystem; + +use Bitrix24\SDK\Core\Exceptions\FileNotFoundException; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Psr\Log\LoggerInterface; +use Symfony\Component\Filesystem\Filesystem; + +readonly class Base64Encoder +{ + private array $allowedRecordFileExtensions; + + public function __construct( + private Filesystem $filesystem, + private \Symfony\Component\Mime\Encoder\Base64Encoder $base64Encoder, + private LoggerInterface $log + ) + { + $this->allowedRecordFileExtensions = ['wav', 'mp3']; + } + + /** + * @param non-empty-string $filename + * @throws InvalidArgumentException + * @throws FileNotFoundException + */ + public function encodeCallRecord(string $filename): string + { + if (!$this->filesystem->exists($filename)) { + throw new FileNotFoundException(sprintf('file %s not found', $filename)); + } + + $fileExt = pathinfo($filename, PATHINFO_EXTENSION); + if (!in_array($fileExt, $this->allowedRecordFileExtensions, true)) { + throw new InvalidArgumentException(sprintf('wrong record file extension %s, allowed types %s', + $fileExt, implode(',', $this->allowedRecordFileExtensions))); + } + + $fileBody = file_get_contents($filename); + if (false === $fileBody) { + throw new InvalidArgumentException(sprintf('cannot read file %s', $filename)); + } + + $fileBody = $this->base64Encoder->encodeString($fileBody); + + $this->log->debug('encodeFile.finish'); + return $fileBody; + } + + /** + * @throws FileNotFoundException|InvalidArgumentException + */ + public function encodeFile(string $filename): string + { + $this->log->debug('encodeFile.start', ['filename' => $filename]); + + if (!$this->filesystem->exists($filename)) { + throw new FileNotFoundException(sprintf('file %s not found', $filename)); + } + + $fileBody = file_get_contents($filename); + if (false === $fileBody) { + throw new InvalidArgumentException(sprintf('cannot read file %s', $filename)); + } + + $fileBody = $this->base64Encoder->encodeString($fileBody); + + $this->log->debug('encodeFile.finish'); + return $fileBody; + } +} \ No newline at end of file diff --git a/src/Infrastructure/HttpClient/RequestId/DefaultRequestIdGenerator.php b/src/Infrastructure/HttpClient/RequestId/DefaultRequestIdGenerator.php new file mode 100644 index 00000000..846df54a --- /dev/null +++ b/src/Infrastructure/HttpClient/RequestId/DefaultRequestIdGenerator.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Infrastructure\HttpClient\RequestId; + +use Symfony\Component\Uid\Uuid; + +class DefaultRequestIdGenerator implements RequestIdGeneratorInterface +{ + private const DEFAULT_REQUEST_ID_HEADER_FIELD_NAME = 'X-Request-ID'; + private const DEFAULT_QUERY_STRING_PARAMETER_NAME = 'bx24_request_id'; + private const KEY_NAME_VARIANTS = [ + 'REQUEST_ID', + 'HTTP_X_REQUEST_ID', + 'UNIQUE_ID' + ]; + + public function getQueryStringParameterName(): string + { + return self::DEFAULT_QUERY_STRING_PARAMETER_NAME; + } + + + private function generate(): string + { + return Uuid::v7()->toRfc4122(); + } + + private function findExists(): ?string + { + $candidate = null; + foreach (self::KEY_NAME_VARIANTS as $key) { + if (!empty($_SERVER[$key])) { + $candidate = $_SERVER[$key]; + break; + } + } + return $candidate; + } + + public function getRequestId(): string + { + $reqId = $this->findExists(); + if ($reqId === null) { + $reqId = $this->generate(); + } + return $reqId; + } + + public function getHeaderFieldName(): string + { + return self::DEFAULT_REQUEST_ID_HEADER_FIELD_NAME; + } +} \ No newline at end of file diff --git a/src/Infrastructure/HttpClient/RequestId/RequestIdGeneratorInterface.php b/src/Infrastructure/HttpClient/RequestId/RequestIdGeneratorInterface.php new file mode 100644 index 00000000..acddc679 --- /dev/null +++ b/src/Infrastructure/HttpClient/RequestId/RequestIdGeneratorInterface.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Infrastructure\HttpClient\RequestId; + +interface RequestIdGeneratorInterface +{ + public function getRequestId(): string; + + public function getHeaderFieldName(): string; + + public function getQueryStringParameterName():string; +} \ No newline at end of file diff --git a/src/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser.php b/src/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser.php new file mode 100644 index 00000000..51fd9c4c --- /dev/null +++ b/src/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Infrastructure\HttpClient\TransportLayer; + +class NetworkTimingsParser +{ + private array $networkTimings; + + /** + * @param array $httpClientResponseInfo + */ + public function __construct(array $httpClientResponseInfo) + { + // time_namelookup: 0.001s + // time_connect: 0.037s + // time_appconnect: 0.000s + // time_pretransfer: 0.037s + // time_redirect: 0.000s + // 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' => $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' => $httpClientResponseInfo['connect_time'], + + // time until the SSL/SSH handshake is completed in MICROSECONDS + // https://curl.se/libcurl/c/CURLINFO_APPCONNECT_TIME.html + // it took from the start until the SSL/SSH connect/handshake to the remote host was completed. + // 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' => $httpClientResponseInfo['appconnect_time'] ?? null, + + // time until the file transfer start in MICROSECONDS + // https://curl.se/libcurl/c/CURLINFO_PRETRANSFER_TIME.html + // It took from the start until the file transfer is just about to begin. + // 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' => $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' => $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' => $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' => $httpClientResponseInfo['total_time'], + ]; + } + + /** + * @return array + */ + public function toArrayWithMicroseconds(): array + { + return $this->networkTimings; + } +} \ No newline at end of file diff --git a/src/Infrastructure/HttpClient/TransportLayer/ResponseInfoParser.php b/src/Infrastructure/HttpClient/TransportLayer/ResponseInfoParser.php new file mode 100644 index 00000000..328af11d --- /dev/null +++ b/src/Infrastructure/HttpClient/TransportLayer/ResponseInfoParser.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Infrastructure\HttpClient\TransportLayer; + +class ResponseInfoParser +{ + private array $responseInfo; + + /** + * @param array $httpClientResponseInfo + */ + public function __construct(array $httpClientResponseInfo) + { + $this->responseInfo = $httpClientResponseInfo; + } + + /** + * @return array[] + */ + public function toArray(): array + { + return [ + // canceled (bool) - true if the response was canceled using ResponseInterface::cancel(), false otherwise + 'canceled' => $this->responseInfo['canceled'], + // error (string|null) - the error message when the transfer was aborted, null otherwise + 'error' => $this->responseInfo['error'], + // http_code (int) - the last response code or 0 when it is not known yet + 'http_code' => $this->responseInfo['http_code'], + // http_method (string) - the HTTP verb of the last request + 'http_method' => $this->responseInfo['http_method'], + // redirect_count (int) - the number of redirects followed while executing the request + 'redirect_count' => $this->responseInfo['redirect_count'], + // redirect_url (string|null) - the resolved location of redirect responses, null otherwise + 'redirect_url' => $this->responseInfo['redirect_url'], + // start_time (float) - the time when the request was sent or 0.0 when it's pending + 'start_time' => $this->responseInfo['start_time'], + // url (string) - the last effective URL of the request + 'url' => $this->responseInfo['url'], + ]; + } +} \ No newline at end of file diff --git a/src/Services/AbstractBatchService.php b/src/Services/AbstractBatchService.php new file mode 100644 index 00000000..f4eafe95 --- /dev/null +++ b/src/Services/AbstractBatchService.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services; + +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +use Psr\Log\LoggerInterface; + +/** + * Class Batch + * + * @package Bitrix24\SDK\Services\CRM\Contact\Service + */ +abstract class AbstractBatchService +{ + protected BatchOperationsInterface $batch; + protected LoggerInterface $log; + + /** + * Batch constructor. + * + * @param BatchOperationsInterface $batch + * @param LoggerInterface $log + */ + public function __construct(BatchOperationsInterface $batch, LoggerInterface $log) + { + $this->batch = $batch; + $this->log = $log; + } +} \ No newline at end of file diff --git a/src/Services/AbstractService.php b/src/Services/AbstractService.php new file mode 100644 index 00000000..9d71d95c --- /dev/null +++ b/src/Services/AbstractService.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services; + +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Money\Currencies\ISOCurrencies; +use Money\Formatter\DecimalMoneyFormatter; +use Psr\Log\LoggerInterface; + +/** + * Class AbstractService + * + * @package Bitrix24\SDK\Services + */ +abstract class AbstractService +{ + /** + * @property-read CoreInterface $core + */ + public CoreInterface $core; + protected LoggerInterface $log; + protected DecimalMoneyFormatter $decimalMoneyFormatter; + + /** + * AbstractService constructor. + * + * @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/AbstractServiceBuilder.php b/src/Services/AbstractServiceBuilder.php new file mode 100644 index 00000000..33edbf89 --- /dev/null +++ b/src/Services/AbstractServiceBuilder.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services; + + +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +use Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Psr\Log\LoggerInterface; + +/** + * Class AbstractServiceBuilder + * + * @package Bitrix24\SDK\Services + */ +abstract class AbstractServiceBuilder +{ + protected CoreInterface $core; + protected BatchOperationsInterface $batch; + protected BulkItemsReaderInterface $bulkItemsReader; + protected LoggerInterface $log; + protected array $serviceCache; + + /** + * AbstractServiceBuilder constructor. + * + * @param CoreInterface $core + * @param BatchOperationsInterface $batch + * @param \Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface $bulkItemsReader + * @param LoggerInterface $log + */ + public function __construct( + CoreInterface $core, + BatchOperationsInterface $batch, + BulkItemsReaderInterface $bulkItemsReader, + LoggerInterface $log + ) { + $this->core = $core; + $this->batch = $batch; + $this->bulkItemsReader = $bulkItemsReader; + $this->log = $log; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/ActivityContentType.php b/src/Services/CRM/Activity/ActivityContentType.php new file mode 100644 index 00000000..57273409 --- /dev/null +++ b/src/Services/CRM/Activity/ActivityContentType.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Activity; + +/** + * @see https://training.bitrix24.com/rest_help/crm/auxiliary/enum/crm_enum_contenttype.php + */ +enum ActivityContentType: int +{ + case default = 0; + case plainText = 1; + case bbCode = 2; + case html = 3; +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/ActivityDirectionType.php b/src/Services/CRM/Activity/ActivityDirectionType.php new file mode 100644 index 00000000..94b893b8 --- /dev/null +++ b/src/Services/CRM/Activity/ActivityDirectionType.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Activity; + +/** + * @see https://training.bitrix24.com/rest_help/crm/auxiliary/enum/crm_enum-activitydirection.php + */ +enum ActivityDirectionType: int +{ + case default = 0; + case incoming = 1; + case outgoing = 2; +} \ 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..f21ab419 --- /dev/null +++ b/src/Services/CRM/Activity/ActivityFetcherBuilder.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Activity; + +use Bitrix24\SDK\Services\AbstractServiceBuilder; +use Bitrix24\SDK\Services\CRM\Contact; +use Bitrix24\SDK\Services\CRM\Deal; +use Bitrix24\SDK\Services\CRM\Product; +use Bitrix24\SDK\Services\CRM\Settings; +use Bitrix24\SDK\Services\CRM\Activity; + +class ActivityFetcherBuilder extends AbstractServiceBuilder +{ + /** + * @return \Bitrix24\SDK\Services\CRM\Activity\ReadModel\EmailFetcher + */ + public function emailFetcher(): Activity\ReadModel\EmailFetcher + { + if (!isset($this->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/ActivityNotifyType.php b/src/Services/CRM/Activity/ActivityNotifyType.php new file mode 100644 index 00000000..6ecbd718 --- /dev/null +++ b/src/Services/CRM/Activity/ActivityNotifyType.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Activity; + +/** + * @see https://training.bitrix24.com/rest_help/crm/auxiliary/enum/crm_enumactivitynotifytype.php + */ +enum ActivityNotifyType: int +{ + case default = 0; + case minutes = 1; + case hours = 2; + case days = 3; +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/ActivityPriority.php b/src/Services/CRM/Activity/ActivityPriority.php new file mode 100644 index 00000000..dec4d9de --- /dev/null +++ b/src/Services/CRM/Activity/ActivityPriority.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Activity; + +/** + * @see https://training.bitrix24.com/rest_help/crm/auxiliary/enum/crm_enum_activitypriority.php + */ +enum ActivityPriority: int +{ + case default = 0; + case low = 1; + case medium = 2; + case high = 3; +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/ActivityStatus.php b/src/Services/CRM/Activity/ActivityStatus.php new file mode 100644 index 00000000..2678b8ca --- /dev/null +++ b/src/Services/CRM/Activity/ActivityStatus.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Activity; + +/** + * @see https://training.bitrix24.com/rest_help/crm/auxiliary/enum/crm_enum_activitystatus.php + */ +enum ActivityStatus: int +{ + case default = 0; + case waiting = 1; + case finished = 2; + case finishedAutomatically = 3; +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/ActivityType.php b/src/Services/CRM/Activity/ActivityType.php new file mode 100644 index 00000000..46e96a59 --- /dev/null +++ b/src/Services/CRM/Activity/ActivityType.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Activity; + +/** + * @see https://training.bitrix24.com/rest_help/crm/auxiliary/enum/crm_enum_activitytype.php + */ +enum ActivityType: int +{ + case default = 0; + case meeting = 1; + case call = 2; + case task = 3; + case letter = 4; + case action = 5; + case userAction = 6; +} \ 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..0d535df5 --- /dev/null +++ b/src/Services/CRM/Activity/ReadModel/EmailFetcher.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Activity\ReadModel; + +use Bitrix24\SDK\Attributes\ApiBatchMethodMetadata; +use Bitrix24\SDK\Attributes\ApiBatchServiceMetadata; +use Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Services\CRM\Activity\Result\Email\EmailActivityItemResult; +use Generator; + +#[ApiBatchServiceMetadata(new Scope(['crm']))] +class EmailFetcher +{ + private BulkItemsReaderInterface $bulkItemsReader; + + /** + * @param BulkItemsReaderInterface $bulkItemsReader + */ + public function __construct(BulkItemsReaderInterface $bulkItemsReader) + { + $this->bulkItemsReader = $bulkItemsReader; + } + + /** + * @return Generator + * @throws BaseException + */ + #[ApiBatchMethodMetadata( + 'crm.activity.list', + 'https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_list.php', + 'Returns in batch mode a list of activity where provider id is an a EMAIL' + )] + 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..c371b266 --- /dev/null +++ b/src/Services/CRM/Activity/ReadModel/OpenLineFetcher.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Activity\ReadModel; + +use Bitrix24\SDK\Attributes\ApiBatchMethodMetadata; +use Bitrix24\SDK\Attributes\ApiBatchServiceMetadata; +use Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Services\CRM\Activity\Result\OpenLine\OpenLineActivityItemResult; +use Generator; + +#[ApiBatchServiceMetadata(new Scope(['crm']))] +class OpenLineFetcher +{ + private BulkItemsReaderInterface $bulkItemsReader; + + /** + * @param BulkItemsReaderInterface $bulkItemsReader + */ + public function __construct(BulkItemsReaderInterface $bulkItemsReader) + { + $this->bulkItemsReader = $bulkItemsReader; + } + + /** + * @return Generator + * @throws BaseException + */ + #[ApiBatchMethodMetadata( + 'crm.activity.list', + 'https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_list.php', + 'Returns in batch mode a list of activity where provider id is an a IMOPENLINES_SESSION' + )] + 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..9ffffa82 --- /dev/null +++ b/src/Services/CRM/Activity/ReadModel/VoximplantFetcher.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Activity\ReadModel; + +use Bitrix24\SDK\Attributes\ApiBatchMethodMetadata; +use Bitrix24\SDK\Attributes\ApiBatchServiceMetadata; +use Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Services\CRM\Activity\Result\ActivityItemResult; +use Bitrix24\SDK\Services\CRM\Activity\Result\OpenLine\OpenLineActivityItemResult; +use Generator; + +#[ApiBatchServiceMetadata(new Scope(['crm']))] +class VoximplantFetcher +{ + private BulkItemsReaderInterface $bulkItemsReader; + + /** + * @param BulkItemsReaderInterface $bulkItemsReader + */ + public function __construct(BulkItemsReaderInterface $bulkItemsReader) + { + $this->bulkItemsReader = $bulkItemsReader; + } + + /** + * @return Generator + * @throws BaseException + */ + #[ApiBatchMethodMetadata( + 'crm.activity.list', + 'https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_list.php', + 'Returns in batch mode a list of activity where provider id is an a VOXIMPLANT_CALL' + )] + 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..b9b205be --- /dev/null +++ b/src/Services/CRM/Activity/ReadModel/WebFormFetcher.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Activity\ReadModel; + +use Bitrix24\SDK\Attributes\ApiBatchMethodMetadata; +use Bitrix24\SDK\Attributes\ApiBatchServiceMetadata; +use Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Services\CRM\Activity\Result\ActivityItemResult; +use Bitrix24\SDK\Services\CRM\Activity\Result\WebForm\WebFormActivityItemResult; +use Generator; + +#[ApiBatchServiceMetadata(new Scope(['crm']))] +class WebFormFetcher +{ + private BulkItemsReaderInterface $bulkItemsReader; + + /** + * @param BulkItemsReaderInterface $bulkItemsReader + */ + public function __construct(BulkItemsReaderInterface $bulkItemsReader) + { + $this->bulkItemsReader = $bulkItemsReader; + } + + /** + * @return Generator + * + * @throws BaseException + */ + #[ApiBatchMethodMetadata( + 'crm.activity.list', + 'https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_list.php', + 'Returns in batch mode a list of activity where provider id is an a CRM_WEBFORM' + )] + 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..214f5271 --- /dev/null +++ b/src/Services/CRM/Activity/Result/ActivitiesResult.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Activity\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class ActivitiesResult extends AbstractResult +{ + /** + * @return \Bitrix24\SDK\Services\CRM\Activity\Result\ActivityItemResult[] + * @throws BaseException + */ + public function getActivities(): array + { + $res = []; + foreach ($this->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..8e819f40 --- /dev/null +++ b/src/Services/CRM/Activity/Result/ActivityItemResult.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Activity\Result; + +use Bitrix24\SDK\Services\CRM\Activity\ActivityContentType; +use Bitrix24\SDK\Services\CRM\Activity\ActivityDirectionType; +use Bitrix24\SDK\Services\CRM\Activity\ActivityNotifyType; +use Bitrix24\SDK\Services\CRM\Activity\ActivityPriority; +use Bitrix24\SDK\Services\CRM\Activity\ActivityStatus; +use Bitrix24\SDK\Services\CRM\Activity\ActivityType; +use Bitrix24\SDK\Services\CRM\Common\Result\AbstractCrmItem; +use Carbon\CarbonImmutable; +use Money\Currency; +use Money\Money; + +/** + * @see https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_fields.php + * + * @property-read int $ID // Activity ID + * @property-read int $OWNER_ID + * @property-read string $OWNER_TYPE_ID + * @property-read ActivityType $TYPE_ID + * @property-read string $PROVIDER_ID + * @property-read string $PROVIDER_TYPE_ID + * @property-read string $PROVIDER_GROUP_ID + * @property-read int $ASSOCIATED_ENTITY_ID // ID of an entity associated with the activity + * @property-read string $SUBJECT + * @property-read string $START_TIME + * @property-read string $END_TIME // Completion time + * @property-read CarbonImmutable $DEADLINE // Deadline + * @property-read boolean $COMPLETED // Completed + * @property-read ActivityStatus $STATUS + * @property-read int $RESPONSIBLE_ID + * @property-read ActivityPriority $PRIORITY + * @property-read ActivityNotifyType $NOTIFY_TYPE // Notification type with crm_enum_activitynotifytype type + * @property-read int $NOTIFY_VALUE + * @property-read string $DESCRIPTION // Description + * @property-read ActivityContentType $DESCRIPTION_TYPE // Description type with crm_enum_contenttype type + * @property-read ActivityDirectionType $DIRECTION // with crm_enum_activity direction type + * @property-read string|null $LOCATION // Location + * @property-read CarbonImmutable $CREATED + * @property-read int $AUTHOR_ID // Activity author ID + * @property-read CarbonImmutable $LAST_UPDATED // Date of the last update date + * @property-read int $EDITOR_ID // Editor + * @property-read array $SETTINGS + * @property-read string|null $ORIGIN_ID + * @property-read string|null $ORIGINATOR_ID + * @property-read int $RESULT_STATUS + * @property-read int $RESULT_STREAM + * @property-read string|null $RESULT_SOURCE_ID + * @property-read array $PROVIDER_PARAMS + * @property-read string|null $PROVIDER_DATA + * @property-read int $RESULT_MARK + * @property-read string|null $RESULT_VALUE + * @property-read Money|null $RESULT_SUM + * @property-read Currency|null $RESULT_CURRENCY_ID + * @property-read int $AUTOCOMPLETE_RULE // Autocompletion + * @property-read string $BINDINGS // Bindings + * @property-read array $COMMUNICATIONS // type crm_activity_communication + * @property-read array $FILES // Added files with diskfile type + * @property-read string $WEBDAV_ELEMENTS + */ +class ActivityItemResult extends AbstractCrmItem +{ +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/Result/ActivityResult.php b/src/Services/CRM/Activity/Result/ActivityResult.php new file mode 100644 index 00000000..c15dcc3c --- /dev/null +++ b/src/Services/CRM/Activity/Result/ActivityResult.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Activity\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class ActivityResult extends AbstractResult +{ + public function activity(): ActivityItemResult + { + return new ActivityItemResult($this->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..77b9fc53 --- /dev/null +++ b/src/Services/CRM/Activity/Result/Email/EmailActivityItemResult.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Activity\Result\Email; + +use Bitrix24\SDK\Services\CRM\Activity\Result\ActivityItemResult; + +/** + * @property-read \Bitrix24\SDK\Services\CRM\Activity\Result\Email\EmailSettings $SETTINGS + */ +class EmailActivityItemResult extends ActivityItemResult +{ + public function __get($offset) + { + if ($offset === 'SETTINGS') { + return new EmailSettings($this->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..bb890e6e --- /dev/null +++ b/src/Services/CRM/Activity/Result/Email/EmailMeta.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Activity\Result\Email; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read string $__email + * @property-read string $from + * @property-read string $replyTo + * @property-read string $to + * @property-read string $cc + * @property-read string $bcc + */ +class EmailMeta extends AbstractItem +{ +} \ No newline at end of file diff --git a/src/Services/CRM/Activity/Result/Email/EmailSettings.php b/src/Services/CRM/Activity/Result/Email/EmailSettings.php new file mode 100644 index 00000000..8e3a1029 --- /dev/null +++ b/src/Services/CRM/Activity/Result/Email/EmailSettings.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Activity\Result\Email; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read bool|null $IS_BATCH_EMAIL + * @property-read array|null $MESSAGE_HEADERS + * @property-read EmailMeta|null $EMAIL_META + */ +class EmailSettings extends AbstractItem +{ + public function __get($offset) + { + if ($offset === 'EMAIL_META') { + if (array_key_exists($offset, $this->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..5fec9612 --- /dev/null +++ b/src/Services/CRM/Activity/Result/OpenLine/OpenLineActivityItemResult.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Activity\Result\OpenLine; + +use Bitrix24\SDK\Services\CRM\Activity\Result\ActivityItemResult; + +class OpenLineActivityItemResult extends ActivityItemResult +{ + /** + * @return \Bitrix24\SDK\Services\CRM\Activity\Result\OpenLine\OpenLineProviderParams + */ + public function getProviderParams(): OpenLineProviderParams + { + return new OpenLineProviderParams($this->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..8ca1c3f9 --- /dev/null +++ b/src/Services/CRM/Activity/Result/OpenLine/OpenLineProviderParams.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Activity\Result\OpenLine; + +class OpenLineProviderParams +{ + private string $userCode; + + /** + * @param string $userCode + */ + public function __construct(string $userCode) + { + $this->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..16b20878 --- /dev/null +++ b/src/Services/CRM/Activity/Result/WebForm/VisitedPageItem.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Activity\Result\WebForm; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read string $HREF + * @property-read int $DATE + * @property-read string $TITLE + */ +class VisitedPageItem extends AbstractItem +{ +} + diff --git a/src/Services/CRM/Activity/Result/WebForm/WebFormActivityItemResult.php b/src/Services/CRM/Activity/Result/WebForm/WebFormActivityItemResult.php new file mode 100644 index 00000000..d36cc0df --- /dev/null +++ b/src/Services/CRM/Activity/Result/WebForm/WebFormActivityItemResult.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Activity\Result\WebForm; + +use Bitrix24\SDK\Services\CRM\Activity\Result\ActivityItemResult; + +class WebFormActivityItemResult extends ActivityItemResult +{ + /** + * @return \Bitrix24\SDK\Services\CRM\Activity\Result\WebForm\WebFormProviderParams + */ + public function getProviderParams(): WebFormProviderParams + { + return new WebFormProviderParams( + $this->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..715459d2 --- /dev/null +++ b/src/Services/CRM/Activity/Result/WebForm/WebFormFieldItem.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Activity\Result\WebForm; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read string $type + * @property-read string $code + * @property-read bool $required + * @property-read string $caption + * @property-read array $value + */ +class WebFormFieldItem extends AbstractItem +{ +} + diff --git a/src/Services/CRM/Activity/Result/WebForm/WebFormMetadata.php b/src/Services/CRM/Activity/Result/WebForm/WebFormMetadata.php new file mode 100644 index 00000000..c1a9c457 --- /dev/null +++ b/src/Services/CRM/Activity/Result/WebForm/WebFormMetadata.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Activity\Result\WebForm; + +class WebFormMetadata +{ + private bool $isUsedUserConsent; + private array $agreements; + private string $ip; + private string $link; + + /** + * @param bool $isUsedUserConsent + * @param array $agreements + * @param string $ip + * @param string $link + */ + public function __construct(bool $isUsedUserConsent, array $agreements, string $ip, string $link) + { + $this->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..e8c8d572 --- /dev/null +++ b/src/Services/CRM/Activity/Result/WebForm/WebFormProviderParams.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Activity\Result\WebForm; + +class WebFormProviderParams +{ + private array $fields; + private WebFormMetadata $webForm; + private array $visitedPages; + + /** + * @param array $fields + * @param \Bitrix24\SDK\Services\CRM\Activity\Result\WebForm\WebFormMetadata $webForm + * @param array $visitedPages + */ + public function __construct(array $fields, WebFormMetadata $webForm, array $visitedPages) + { + $this->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..6ef0993d --- /dev/null +++ b/src/Services/CRM/Activity/Service/Activity.php @@ -0,0 +1,452 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Activity\Service; + +use Bitrix24\SDK\Attributes\ApiBatchServiceMetadata; +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\AddedItemResult; +use Bitrix24\SDK\Core\Result\DeletedItemResult; +use Bitrix24\SDK\Core\Result\FieldsResult; +use Bitrix24\SDK\Core\Result\UpdatedItemResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\CRM\Activity\Result\ActivitiesResult; +use Bitrix24\SDK\Services\CRM\Activity\Result\ActivityResult; +use Psr\Log\LoggerInterface; + +#[ApiServiceMetadata(new Scope(['crm']))] +class Activity extends AbstractService +{ + public Batch $batch; + + /** + * Contact constructor. + * + * @param Batch $batch + * @param CoreInterface $core + * @param LoggerInterface $log + */ + public function __construct(Batch $batch, CoreInterface $core, LoggerInterface $log) + { + parent::__construct($core, $log); + $this->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?: int, + * TYPE_ID?: int, + * 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 + */ + #[ApiEndpointMetadata( + 'crm.activity.add', + 'https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_add.php', + 'Creates and adds a new activity.' + )] + 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 + */ + #[ApiEndpointMetadata( + 'crm.activity.delete', + 'https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_delete.php', + 'Deletes the specified activity and all the associated objects.' + )] + 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 + */ + #[ApiEndpointMetadata( + 'crm.activity.fields', + 'https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_fields.php', + 'Returns the description of activity fields' + )] + 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 + */ + #[ApiEndpointMetadata( + 'crm.activity.get', + 'https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_get.php', + 'Returns activity by the specified activity ID' + )] + 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 + */ + #[ApiEndpointMetadata( + 'crm.activity.list', + 'https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_list.php', + 'Returns a list of activity selected by the filter specified as the parameter. See the example for the filter notation.' + )] + 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 + */ + #[ApiEndpointMetadata( + 'crm.activity.update', + 'https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_update.php', + 'Updates the specified (existing) activity.' + )] + 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 BaseException + * @throws 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..06dba9b6 --- /dev/null +++ b/src/Services/CRM/Activity/Service/Batch.php @@ -0,0 +1,240 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Activity\Service; + +use Bitrix24\SDK\Attributes\ApiBatchMethodMetadata; +use Bitrix24\SDK\Attributes\ApiBatchServiceMetadata; +use Bitrix24\SDK\Core\Contracts\DeletedItemResultInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +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\Activity\Result\ActivityItemResult; +use Generator; + +#[ApiBatchServiceMetadata(new Scope(['crm']))] +class Batch extends AbstractBatchService +{ + /** + * batch list method + * + * @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|null $limit + * + * @return Generator + * @throws BaseException + */ + #[ApiBatchMethodMetadata( + 'crm.activity.list', + 'https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_list.php', + 'Returns in batch mode a list of activity' + )] + 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 BaseException + */ + #[ApiBatchMethodMetadata( + 'crm.activity.add', + 'https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_add.php', + 'Adds in batch mode a new activity' + )] + 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 + * @throws BaseException + */ + #[ApiBatchMethodMetadata( + 'crm.activity.delete', + 'https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_delete.php', + 'Delete in batch mode activity' + )] + 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 new file mode 100644 index 00000000..b3eb8964 --- /dev/null +++ b/src/Services/CRM/CRMServiceBuilder.php @@ -0,0 +1,207 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM; + +use Bitrix24\SDK\Services\AbstractServiceBuilder; + +class CRMServiceBuilder extends AbstractServiceBuilder +{ + public function settings(): Settings\Service\Settings + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Settings\Service\Settings($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + public function dealContact(): Deal\Service\DealContact + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Deal\Service\DealContact($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + public function dealCategory(): Deal\Service\DealCategory + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Deal\Service\DealCategory($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + public function deal(): Deal\Service\Deal + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Deal\Service\Deal( + new Deal\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + + public function dealUserfield(): Deal\Service\DealUserfield + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Deal\Service\DealUserfield( + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + + public function contact(): Contact\Service\Contact + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Contact\Service\Contact( + new Contact\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + + public function contactUserfield(): Contact\Service\ContactUserfield + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Contact\Service\ContactUserfield( + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * @return Deal\Service\DealProductRows + */ + public function dealProductRows(): Deal\Service\DealProductRows + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Deal\Service\DealProductRows($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + public function dealCategoryStage(): Deal\Service\DealCategoryStage + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Deal\Service\DealCategoryStage($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + public function product(): Product\Service\Product + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Product\Service\Product( + new Product\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + + public function userfield(): Userfield\Service\Userfield + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Userfield\Service\Userfield( + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + + 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__]; + } + + 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__]; + } + + 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__]; + } + + public function item(): Item\Service\Item + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Item\Service\Item( + new Item\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + + public function duplicate(): Duplicates\Service\Duplicate + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Duplicates\Service\Duplicate( + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Common/Result/AbstractCrmItem.php b/src/Services/CRM/Common/Result/AbstractCrmItem.php new file mode 100644 index 00000000..a2542cbf --- /dev/null +++ b/src/Services/CRM/Common/Result/AbstractCrmItem.php @@ -0,0 +1,247 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Common\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; +use Bitrix24\SDK\Services\CRM\Activity\ActivityContentType; +use Bitrix24\SDK\Services\CRM\Activity\ActivityDirectionType; +use Bitrix24\SDK\Services\CRM\Activity\ActivityNotifyType; +use Bitrix24\SDK\Services\CRM\Activity\ActivityPriority; +use Bitrix24\SDK\Services\CRM\Activity\ActivityStatus; +use Bitrix24\SDK\Services\CRM\Activity\ActivityType; +use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\Email; +use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\InstantMessenger; +use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\Phone; +use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\PhoneValueType; +use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\Website; +use Bitrix24\SDK\Services\CRM\Deal\Result\DealSemanticStage; +use Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNotFoundException; +use Carbon\CarbonImmutable; +use Money\Currency; +use Money\Money; +use MoneyPHP\Percentage\Percentage; + +class AbstractCrmItem extends AbstractItem +{ + private Currency $currency; + private const CRM_USERFIELD_PREFIX = 'UF_CRM_'; + + /** + * @param int|string $offset + * + * @return bool|CarbonImmutable|int|mixed|null + */ + public function __get($offset) + { + // todo move to separate service + // + // - add user fields with custom user types + // - add inheritance for user types + + switch ($offset) { + case 'ID': + case 'ASSIGNED_BY_ID': + case 'RESPONSIBLE_ID': + case 'CREATED_BY_ID': + case 'MODIFY_BY_ID': + case 'createdBy': + case 'updatedBy': + case 'movedBy': + case 'begindate': + case 'closedate': + case 'opportunity': + case 'opportunityAccount': + case 'taxValueAccount': + case 'taxValue': + case 'LEAD_ID': + case 'CONTACT_ID': + case 'QUOTE_ID': + case 'OWNER_ID': + case 'SORT': + case 'id': + case 'categoryId': + case 'webformId': + case 'assignedById': + case 'contactId': + case 'lastActivityBy': + case 'AUTHOR_ID': + case 'EDITOR_ID': + case 'RESULT_MARK': + case 'RESULT_STATUS': + case 'RESULT_STREAM': + case 'LAST_ACTIVITY_BY': + case 'ADDRESS_LOC_ADDR_ID': + if ($this->data[$offset] !== '' && $this->data[$offset] !== null) { + return (int)$this->data[$offset]; + } + + return null; + case 'COMPANY_ID': + case 'companyId': + case 'mycompanyId': + if ($this->data[$offset] !== '' && $this->data[$offset] !== null && $this->data[$offset] !== '0') { + return (int)$this->data[$offset]; + } + return null; + case 'EXPORT': + case 'HAS_PHONE': + case 'HAS_EMAIL': + case 'HAS_IMOL': + case 'OPENED': + case 'opened': + case 'IS_MANUAL_OPPORTUNITY': + case 'isManualOpportunity': + case 'CLOSED': + case 'IS_NEW': + case 'IS_LOCKED': + case 'IS_RECURRING': + case 'IS_RETURN_CUSTOMER': + case 'IS_REPEATED_APPROACH': + case 'TAX_INCLUDED': + case 'CUSTOMIZED': + case 'COMPLETED': + return $this->data[$offset] === 'Y'; + case 'DATE_CREATE': + case 'CREATED_DATE': + case 'CREATED': + case 'DEADLINE': + case 'LAST_UPDATED': + case 'DATE_MODIFY': + case 'BIRTHDATE': + case 'BEGINDATE': + case 'CLOSEDATE': + case 'createdTime': + case 'updatedTime': + case 'movedTime': + case 'lastActivityTime': + case 'LAST_ACTIVITY_TIME': + if ($this->data[$offset] !== '') { + return CarbonImmutable::createFromFormat(DATE_ATOM, $this->data[$offset]); + } + + return null; + case 'PRICE_EXCLUSIVE': + case 'PRICE_NETTO': + case 'PRICE_BRUTTO': + case 'PRICE': + case 'DISCOUNT_SUM': + case 'RESULT_SUM': + if ($this->data[$offset] !== '' && $this->data[$offset] !== null) { + $var = $this->data[$offset] * 100; + return new Money((string)$var, new Currency($this->currency->getCode())); + } + return null; + case 'RESULT_CURRENCY_ID': + if ($this->data[$offset] !== '' && $this->data[$offset] !== null) { + return new Currency($this->data[$offset]); + } + return null; + case 'PHONE': + if (!$this->isKeyExists($offset)) { + return []; + } + + $items = []; + foreach ($this->data[$offset] as $item) { + $items[] = new Phone($item); + } + return $items; + case 'EMAIL': + if (!$this->isKeyExists($offset)) { + return []; + } + + $items = []; + foreach ($this->data[$offset] as $item) { + $items[] = new Email($item); + } + return $items; + case 'WEB': + if (!$this->isKeyExists($offset)) { + return []; + } + + $items = []; + foreach ($this->data[$offset] as $item) { + $items[] = new Website($item); + } + return $items; + case 'IM': + if (!$this->isKeyExists($offset)) { + return []; + } + + $items = []; + foreach ($this->data[$offset] as $item) { + $items[] = new InstantMessenger($item); + } + return $items; + case 'currencyId': + case 'accountCurrencyId': + case 'CURRENCY_ID': + return new Currency($this->data[$offset]); + case 'STAGE_SEMANTIC_ID': + if ($this->data[$offset] !== null) { + return DealSemanticStage::from($this->data[$offset]); + } + return null; + case 'DISCOUNT_TYPE_ID': + return DiscountType::from($this->data[$offset]); + case 'DISCOUNT_RATE': + return new Percentage((string)$this->data[$offset]); + case 'TYPE_ID': + return ActivityType::from((int)$this->data[$offset]); + case 'STATUS': + return ActivityStatus::from((int)$this->data[$offset]); + case 'PRIORITY': + return ActivityPriority::from((int)$this->data[$offset]); + case 'NOTIFY_TYPE': + return ActivityNotifyType::from((int)$this->data[$offset]); + case 'DESCRIPTION_TYPE': + return ActivityContentType::from((int)$this->data[$offset]); + case 'DIRECTION': + return ActivityDirectionType::from((int)$this->data[$offset]); + default: + return $this->data[$offset] ?? null; + } + } + + /** + * get userfield by field name + * + * @param string $fieldName + * + * @return mixed|null + * @throws UserfieldNotFoundException + */ + protected function getKeyWithUserfieldByFieldName(string $fieldName): mixed + { + if (!str_starts_with($fieldName, self::CRM_USERFIELD_PREFIX)) { + $fieldName = self::CRM_USERFIELD_PREFIX . $fieldName; + } + if (!$this->isKeyExists($fieldName)) { + throw new UserfieldNotFoundException(sprintf('crm userfield not found by field name %s', $fieldName)); + } + + return $this->$fieldName; + } + + public function __construct(array $data, Currency $currency = null) + { + parent::__construct($data); + if ($currency !== null) { + $this->currency = $currency; + } + } +} \ No newline at end of file diff --git a/src/Services/CRM/Common/Result/DiscountType.php b/src/Services/CRM/Common/Result/DiscountType.php new file mode 100644 index 00000000..3b915fa0 --- /dev/null +++ b/src/Services/CRM/Common/Result/DiscountType.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Common\Result; + +enum DiscountType: int +{ + case monetary = 1; + case percentage = 2; +} \ No newline at end of file diff --git a/src/Services/CRM/Common/Result/SystemFields/Types/Email.php b/src/Services/CRM/Common/Result/SystemFields/Types/Email.php new file mode 100644 index 00000000..0dc80e13 --- /dev/null +++ b/src/Services/CRM/Common/Result/SystemFields/Types/Email.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read string $VALUE + * @property-read int $ID + * @property-read PhoneValueType $VALUE_TYPE + */ +class Email extends AbstractItem +{ + public function __get($offset) + { + return match ($offset) { + 'VALUE' => $this->data[$offset], + 'ID' => (int)$this->data['ID'], + 'VALUE_TYPE' => EmailValueType::from($this->data['VALUE_TYPE']), + default => parent::__get($offset), + }; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Common/Result/SystemFields/Types/EmailValueType.php b/src/Services/CRM/Common/Result/SystemFields/Types/EmailValueType.php new file mode 100644 index 00000000..083e3d0d --- /dev/null +++ b/src/Services/CRM/Common/Result/SystemFields/Types/EmailValueType.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types; + +enum EmailValueType: string +{ + case work = 'WORK'; + case home = 'HOME'; + case other = 'OTHER'; + case mailing = 'MAILING'; +} \ No newline at end of file diff --git a/src/Services/CRM/Common/Result/SystemFields/Types/InstantMessenger.php b/src/Services/CRM/Common/Result/SystemFields/Types/InstantMessenger.php new file mode 100644 index 00000000..76fd1419 --- /dev/null +++ b/src/Services/CRM/Common/Result/SystemFields/Types/InstantMessenger.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read string $VALUE + * @property-read int $ID + * @property-read PhoneValueType $VALUE_TYPE + */ +class InstantMessenger extends AbstractItem +{ + public function __get($offset) + { + return match ($offset) { + 'VALUE' => $this->data[$offset], + 'ID' => (int)$this->data['ID'], + 'VALUE_TYPE' => EmailValueType::from($this->data['VALUE_TYPE']), + default => parent::__get($offset), + }; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Common/Result/SystemFields/Types/InstantMessengerValueType.php b/src/Services/CRM/Common/Result/SystemFields/Types/InstantMessengerValueType.php new file mode 100644 index 00000000..43e57385 --- /dev/null +++ b/src/Services/CRM/Common/Result/SystemFields/Types/InstantMessengerValueType.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types; + +enum InstantMessengerValueType: string +{ + case facebook = 'FACEBOOK'; + case telegram = 'TELEGRAM'; + case vk = 'VK'; + case skype = 'SKYPE'; + case viber = 'VIBER'; + case instagram = 'INSTAGRAM'; + case bitrix24 = 'BITRIX24'; + case openline = 'OPENLINE'; + case imol = 'IMOL'; + case icq = 'ICQ'; + case msn = 'MSN'; + case jabber = 'JABBER'; + case other = 'OTHER'; +} \ No newline at end of file diff --git a/src/Services/CRM/Common/Result/SystemFields/Types/Phone.php b/src/Services/CRM/Common/Result/SystemFields/Types/Phone.php new file mode 100644 index 00000000..e981762d --- /dev/null +++ b/src/Services/CRM/Common/Result/SystemFields/Types/Phone.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read string $VALUE + * @property-read int $ID + * @property-read PhoneValueType $VALUE_TYPE + */ +class Phone extends AbstractItem +{ + public function __get($offset) + { + return match ($offset) { + 'VALUE' => $this->data[$offset], + 'ID' => (int)$this->data['ID'], + 'VALUE_TYPE' => PhoneValueType::from($this->data['VALUE_TYPE']), + default => parent::__get($offset), + }; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Common/Result/SystemFields/Types/PhoneValueType.php b/src/Services/CRM/Common/Result/SystemFields/Types/PhoneValueType.php new file mode 100644 index 00000000..04c010dc --- /dev/null +++ b/src/Services/CRM/Common/Result/SystemFields/Types/PhoneValueType.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types; + +enum PhoneValueType:string +{ + case work='WORK'; + case mobile='MOBILE'; + case fax='FAX'; + case home='HOME'; + case pager='PAGER'; + case mailing='MAILING'; + case other='OTHER'; +} \ No newline at end of file diff --git a/src/Services/CRM/Common/Result/SystemFields/Types/Website.php b/src/Services/CRM/Common/Result/SystemFields/Types/Website.php new file mode 100644 index 00000000..bd533bba --- /dev/null +++ b/src/Services/CRM/Common/Result/SystemFields/Types/Website.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read string $VALUE + * @property-read int $ID + * @property-read PhoneValueType $VALUE_TYPE + */ +class Website extends AbstractItem +{ + public function __get($offset) + { + return match ($offset) { + 'VALUE' => $this->data[$offset], + 'ID' => (int)$this->data['ID'], + 'VALUE_TYPE' => EmailValueType::from($this->data['VALUE_TYPE']), + default => parent::__get($offset), + }; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Common/Result/SystemFields/Types/WebsiteValueType.php b/src/Services/CRM/Common/Result/SystemFields/Types/WebsiteValueType.php new file mode 100644 index 00000000..229b905b --- /dev/null +++ b/src/Services/CRM/Common/Result/SystemFields/Types/WebsiteValueType.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types; + +enum WebsiteValueType: string +{ + case work = 'WORK'; + case home = 'HOME'; + case facebook = 'FACEBOOK'; + case vk = 'VK'; + case livejournal = 'LIVEJOURNAL'; + case twitter = 'TWITTER'; + case other = 'OTHER'; +} \ No newline at end of file diff --git a/src/Services/CRM/Contact/Result/ContactItemResult.php b/src/Services/CRM/Contact/Result/ContactItemResult.php new file mode 100644 index 00000000..357de417 --- /dev/null +++ b/src/Services/CRM/Contact/Result/ContactItemResult.php @@ -0,0 +1,88 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Contact\Result; + +use Bitrix24\SDK\Services\CRM\Common\Result\AbstractCrmItem; +use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\Email; +use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\InstantMessenger; +use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\Phone; +use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\Website; +use Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNotFoundException; +use Carbon\CarbonImmutable; + +/** + * @property-read int $ADDRESS_LOC_ADDR_ID + * @property-read string|null $ADDRESS + * @property-read string|null $ADDRESS_2 + * @property-read string|null $ADDRESS_CITY + * @property-read string|null $ADDRESS_COUNTRY + * @property-read string|null $ADDRESS_COUNTRY_CODE + * @property-read string|null $ADDRESS_POSTAL_CODE + * @property-read string|null $ADDRESS_PROVINCE + * @property-read string|null $ADDRESS_REGION + * @property-read int $ASSIGNED_BY_ID + * @property-read CarbonImmutable|null $BIRTHDATE + * @property-read string|null $COMMENTS + * @property-read int|null $COMPANY_ID + * @property-read array|null $COMPANY_IDS + * @property-read int $CREATED_BY_ID + * @property-read CarbonImmutable $DATE_CREATE + * @property-read CarbonImmutable $DATE_MODIFY + * @property-read int|null $FACE_ID + * @property-read bool $EXPORT + * @property-read Email[] $EMAIL + * @property-read int $ID + * @property-read bool $HAS_EMAIL + * @property-read bool $HAS_IMOL + * @property-read bool $HAS_PHONE + * @property-read string|null $HONORIFIC + * @property-read InstantMessenger[] $IM + * @property-read int|null $LEAD_ID + * @property-read CarbonImmutable $LAST_ACTIVITY_TIME + * @property-read int $LAST_ACTIVITY_BY + * @property-read string|null $LAST_NAME + * @property-read string|null $LINK + * @property-read int $MODIFY_BY_ID + * @property-read string $NAME + * @property-read string|null $ORIGIN_ID + * @property-read string|null $ORIGINATOR_ID + * @property-read string|null $ORIGIN_VERSION + * @property-read string $OPENED + * @property-read Phone[] $PHONE + * @property-read string|null $POST + * @property-read string|null $PHOTO + * @property-read string|null $SECOND_NAME + * @property-read string|null $SOURCE_DESCRIPTION + * @property-read string|null $SOURCE_ID + * @property-read string|null $TYPE_ID + * @property-read string|null $UTM_CAMPAIGN + * @property-read string|null $UTM_CONTENT + * @property-read string|null $UTM_MEDIUM + * @property-read string|null $UTM_SOURCE + * @property-read string|null $UTM_TERM + * @property-read Website[] $WEB + */ +class ContactItemResult extends AbstractCrmItem +{ + /** + * @param string $userfieldName + * + * @return mixed|null + * @throws UserfieldNotFoundException + */ + public function getUserfieldByFieldName(string $userfieldName): mixed + { + return $this->getKeyWithUserfieldByFieldName($userfieldName); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Contact/Result/ContactResult.php b/src/Services/CRM/Contact/Result/ContactResult.php new file mode 100644 index 00000000..79a15253 --- /dev/null +++ b/src/Services/CRM/Contact/Result/ContactResult.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Contact\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +/** + * Class ContactResult + * + * @package Bitrix24\SDK\Services\CRM\Contact\Result + */ +class ContactResult extends AbstractResult +{ + public function contact(): ContactItemResult + { + return new ContactItemResult($this->getCoreResponse()->getResponseData()->getResult()); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Contact/Result/ContactUserfieldItemResult.php b/src/Services/CRM/Contact/Result/ContactUserfieldItemResult.php new file mode 100644 index 00000000..310915e2 --- /dev/null +++ b/src/Services/CRM/Contact/Result/ContactUserfieldItemResult.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Contact\Result; + +use Bitrix24\SDK\Services\CRM\Userfield\Result\AbstractUserfieldItemResult; + +class ContactUserfieldItemResult extends AbstractUserfieldItemResult +{ +} \ No newline at end of file diff --git a/src/Services/CRM/Contact/Result/ContactUserfieldResult.php b/src/Services/CRM/Contact/Result/ContactUserfieldResult.php new file mode 100644 index 00000000..95f89f53 --- /dev/null +++ b/src/Services/CRM/Contact/Result/ContactUserfieldResult.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Contact\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class ContactUserfieldResult extends AbstractResult +{ + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function userfieldItem(): ContactUserfieldItemResult + { + 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 new file mode 100644 index 00000000..c5a1ff95 --- /dev/null +++ b/src/Services/CRM/Contact/Result/ContactUserfieldsResult.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Contact\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class ContactUserfieldsResult extends AbstractResult +{ + /** + * @return ContactUserfieldItemResult[] + * @throws BaseException + */ + public function getUserfields(): array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { + $res[] = new ContactUserfieldItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Contact/Result/ContactsResult.php b/src/Services/CRM/Contact/Result/ContactsResult.php new file mode 100644 index 00000000..120a2fc3 --- /dev/null +++ b/src/Services/CRM/Contact/Result/ContactsResult.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Contact\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +/** + * Class ContactsResult + * + * @package Bitrix24\SDK\Services\CRM\Contact\Result + */ +class ContactsResult extends AbstractResult +{ + /** + * @return ContactItemResult[] + * @throws BaseException + */ + public function getContacts(): array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { + $res[] = new ContactItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Contact/Service/Batch.php b/src/Services/CRM/Contact/Service/Batch.php new file mode 100644 index 00000000..9c280a92 --- /dev/null +++ b/src/Services/CRM/Contact/Service/Batch.php @@ -0,0 +1,277 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Contact\Service; + +use Bitrix24\SDK\Attributes\ApiBatchMethodMetadata; +use Bitrix24\SDK\Attributes\ApiBatchServiceMetadata; +use Bitrix24\SDK\Core\Credentials\Scope; +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\AbstractBatchService; +use Bitrix24\SDK\Services\CRM\Contact\Result\ContactItemResult; +use Generator; + +#[ApiBatchServiceMetadata(new Scope(['crm']))] +class Batch extends AbstractBatchService +{ + /** + * batch list method + * + * @param array{ + * ID?: string, + * HONORIFIC?: string, + * NAME?: string, + * SECOND_NAME?: string, + * LAST_NAME?: string, + * PHOTO?: string, + * BIRTHDATE?: string, + * TYPE_ID?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: 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?: string, + * COMMENTS?: string, + * OPENED?: string, + * EXPORT?: string, + * HAS_PHONE?: string, + * HAS_EMAIL?: string, + * HAS_IMOL?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * COMPANY_ID?: string, + * COMPANY_IDS?: string, + * LEAD_ID?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * ORIGIN_VERSION?: string, + * FACE_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, + * } $order + * + * @param array{ + * ID?: int, + * HONORIFIC?: string, + * NAME?: string, + * SECOND_NAME?: string, + * LAST_NAME?: string, + * PHOTO?: string, + * BIRTHDATE?: string, + * TYPE_ID?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: 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, + * COMMENTS?: string, + * OPENED?: string, + * EXPORT?: string, + * HAS_PHONE?: string, + * HAS_EMAIL?: string, + * HAS_IMOL?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * COMPANY_ID?: string, + * COMPANY_IDS?: string, + * LEAD_ID?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * ORIGIN_VERSION?: string, + * FACE_ID?: int, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string, + * PHONE?: string, + * EMAIL?: string, + * 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 + * + * @return Generator + * @throws BaseException + */ + #[ApiBatchMethodMetadata( + 'crm.contact.list', + 'https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_list.php', + 'Returns in batch mode a list of contacts' + )] + 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.contact.list', $order, $filter, $select, $limit) as $key => $value) { + yield $key => new ContactItemResult($value); + } + } + + /** + * Batch adding contacts + * + * @param array $contacts + * + * @return Generator + * @throws BaseException + */ + #[ApiBatchMethodMetadata( + 'crm.contact.add', + 'https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_add.php', + 'Add in batch mode a list of contacts' + )] + public function add(array $contacts): Generator + { + $items = []; + foreach ($contacts as $contact) { + $items[] = [ + 'fields' => $contact, + ]; + } + foreach ($this->batch->addEntityItems('crm.contact.add', $items) as $key => $item) { + yield $key => new AddedItemBatchResult($item); + } + } + + /** + * Batch update contacts + * + * Update elements in array with structure + * element_id => [ // contact id + * 'fields' => [], // contact fields to update + * 'params' => [] + * ] + * + * @param array $entityItems + * @return Generator + * @throws BaseException + */ + #[ApiBatchMethodMetadata( + 'crm.contact.update', + 'https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_update.php', + 'Update in batch mode a list of contacts' + )] + public function update(array $entityItems): Generator + { + foreach ($this->batch->updateEntityItems('crm.contact.update', $entityItems) as $key => $item) { + yield $key => new UpdatedItemBatchResult($item); + } + } + + /** + * Batch delete contact items + * + * @param int[] $contactId + * + * @return Generator + * @throws BaseException + */ + #[ApiBatchMethodMetadata( + 'crm.contact.delete', + 'https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_delete.php', + 'Delete in batch mode a list of contacts' + )] + 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/Contact/Service/Contact.php b/src/Services/CRM/Contact/Service/Contact.php new file mode 100644 index 00000000..2a74c331 --- /dev/null +++ b/src/Services/CRM/Contact/Service/Contact.php @@ -0,0 +1,474 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Contact\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\AddedItemResult; +use Bitrix24\SDK\Core\Result\DeletedItemResult; +use Bitrix24\SDK\Core\Result\FieldsResult; +use Bitrix24\SDK\Core\Result\UpdatedItemResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\CRM\Contact\Result\ContactResult; +use Bitrix24\SDK\Services\CRM\Contact\Result\ContactsResult; +use Psr\Log\LoggerInterface; + +#[ApiServiceMetadata(new Scope(['crm']))] +class Contact extends AbstractService +{ + public Batch $batch; + + /** + * Contact constructor. + * + * @param Batch $batch + * @param CoreInterface $core + * @param LoggerInterface $log + */ + public function __construct(Batch $batch, CoreInterface $core, LoggerInterface $log) + { + parent::__construct($core, $log); + $this->batch = $batch; + } + + /** + * Creates and adds a new contact. + * + * @link https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_add.php + * + * @param array{ + * ID?: int, + * HONORIFIC?: string, + * NAME?: string, + * SECOND_NAME?: string, + * LAST_NAME?: string, + * PHOTO?: string, + * BIRTHDATE?: string, + * TYPE_ID?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: 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, + * COMMENTS?: string, + * OPENED?: string, + * EXPORT?: string, + * HAS_PHONE?: string, + * HAS_EMAIL?: string, + * HAS_IMOL?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * COMPANY_ID?: string, + * COMPANY_IDS?: string, + * LEAD_ID?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * ORIGIN_VERSION?: string, + * FACE_ID?: int, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string, + * PHONE?: string, + * EMAIL?: string, + * WEB?: string, + * IM?: string, + * } $fields + * + * @param array{ + * REGISTER_SONET_EVENT?: string + * } $params + * + * @return AddedItemResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.contact.add', + 'https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_add.php', + 'Creates a new contact.' + )] + public function add(array $fields, array $params = ['REGISTER_SONET_EVENT' => 'N']): AddedItemResult + { + return new AddedItemResult( + $this->core->call( + 'crm.contact.add', + [ + 'fields' => $fields, + 'params' => $params, + ] + ) + ); + } + + /** + * Deletes the specified contact and all the associated objects. + * + * @link https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_delete.php + * + * @param int $contactId + * + * @return DeletedItemResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.contact.delete', + 'https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_delete.php', + 'Delete a contact.' + )] + public function delete(int $contactId): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call( + 'crm.contact.delete', + [ + 'id' => $contactId, + ] + ) + ); + } + + /** + * Returns the description of contact + * + * @link https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_fields.php + * + * @return FieldsResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.contact.fields', + 'https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_fields.php', + 'Returns the description of contact' + )] + public function fields(): FieldsResult + { + return new FieldsResult($this->core->call('crm.contact.fields')); + } + + /** + * Returns a contact by the specified contact ID + * + * @link https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_get.php + * + * @param int $contactId + * + * @return ContactResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.contact.get', + 'https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_get.php', + 'Returns a contact by the specified contact ID' + )] + public function get(int $contactId): ContactResult + { + return new ContactResult( + $this->core->call( + 'crm.contact.get', + [ + 'id' => $contactId, + ] + ) + ); + } + + /** + * Returns a list of contacts selected by the filter specified as the parameter. See the example for the filter notation. + * + * @link https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_list.php + * + * @param array{ + * ID?: int, + * HONORIFIC?: string, + * NAME?: string, + * SECOND_NAME?: string, + * LAST_NAME?: string, + * PHOTO?: string, + * BIRTHDATE?: string, + * TYPE_ID?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: 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, + * COMMENTS?: string, + * OPENED?: string, + * EXPORT?: string, + * HAS_PHONE?: string, + * HAS_EMAIL?: string, + * HAS_IMOL?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * COMPANY_ID?: string, + * COMPANY_IDS?: string, + * LEAD_ID?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * ORIGIN_VERSION?: string, + * FACE_ID?: int, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string, + * PHONE?: string, + * EMAIL?: string, + * WEB?: string, + * IM?: string, + * } $order + * + * @param array{ + * ID?: int, + * HONORIFIC?: string, + * NAME?: string, + * SECOND_NAME?: string, + * LAST_NAME?: string, + * PHOTO?: string, + * BIRTHDATE?: string, + * TYPE_ID?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: 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, + * COMMENTS?: string, + * OPENED?: string, + * EXPORT?: string, + * HAS_PHONE?: string, + * HAS_EMAIL?: string, + * HAS_IMOL?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * COMPANY_ID?: string, + * COMPANY_IDS?: string, + * LEAD_ID?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * ORIGIN_VERSION?: string, + * FACE_ID?: int, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string, + * PHONE?: string, + * EMAIL?: string, + * 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 $start + * + * @return ContactsResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.contact.list', + 'https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_list.php', + 'Returns a list of contacts selected by the filter specified as the parameter. ' + )] + public function list(array $order, array $filter, array $select, int $start): ContactsResult + { + return new ContactsResult( + $this->core->call( + 'crm.contact.list', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $start, + ] + ) + ); + } + + /** + * @param int $contactId + * @param array{ + * ID?: int, + * HONORIFIC?: string, + * NAME?: string, + * SECOND_NAME?: string, + * LAST_NAME?: string, + * PHOTO?: string, + * BIRTHDATE?: string, + * TYPE_ID?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: 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, + * COMMENTS?: string, + * OPENED?: string, + * EXPORT?: string, + * HAS_PHONE?: string, + * HAS_EMAIL?: string, + * HAS_IMOL?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * COMPANY_ID?: string, + * COMPANY_IDS?: string, + * LEAD_ID?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * ORIGIN_VERSION?: string, + * FACE_ID?: int, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string, + * PHONE?: string, + * EMAIL?: string, + * WEB?: string, + * IM?: string, + * } $fields + * + * @param array{ + * REGISTER_SONET_EVENT?: string + * } $params + * + * @return UpdatedItemResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.contact.update', + 'https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_update.php', + 'Update contact by id' + )] + public function update(int $contactId, array $fields, array $params = []): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call( + 'crm.contact.update', + [ + 'id' => $contactId, + 'fields' => $fields, + 'params' => $params, + ] + ) + ); + } + + /** + * @param array{ + * ID?: int, + * HONORIFIC?: string, + * NAME?: string, + * SECOND_NAME?: string, + * LAST_NAME?: string, + * PHOTO?: string, + * BIRTHDATE?: string, + * TYPE_ID?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: 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, + * COMMENTS?: string, + * OPENED?: string, + * EXPORT?: string, + * HAS_PHONE?: string, + * HAS_EMAIL?: string, + * HAS_IMOL?: string, + * ASSIGNED_BY_ID?: string, + * CREATED_BY_ID?: string, + * MODIFY_BY_ID?: string, + * DATE_CREATE?: string, + * DATE_MODIFY?: string, + * COMPANY_ID?: string, + * COMPANY_IDS?: string, + * LEAD_ID?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * ORIGIN_VERSION?: string, + * FACE_ID?: int, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string, + * PHONE?: string, + * EMAIL?: string, + * WEB?: string, + * IM?: 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/Contact/Service/ContactUserfield.php b/src/Services/CRM/Contact/Service/ContactUserfield.php new file mode 100644 index 00000000..1b5a2639 --- /dev/null +++ b/src/Services/CRM/Contact/Service/ContactUserfield.php @@ -0,0 +1,242 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Contact\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\AddedItemResult; +use Bitrix24\SDK\Core\Result\DeletedItemResult; +use Bitrix24\SDK\Core\Result\UpdatedItemResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\CRM\Contact\Result\ContactUserfieldResult; +use Bitrix24\SDK\Services\CRM\Contact\Result\ContactUserfieldsResult; +use Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNameIsTooLongException; + +#[ApiServiceMetadata(new Scope(['crm']))] +class ContactUserfield extends AbstractService +{ + /** + * @param array{ + * ID?: string, + * ENTITY_ID?: string, + * FIELD_NAME?: string, + * USER_TYPE_ID?: string, + * XML_ID?: string, + * SORT?: string, + * MULTIPLE?: string, + * MANDATORY?: string, + * SHOW_FILTER?: string, + * SHOW_IN_LIST?: string, + * EDIT_IN_LIST?: string, + * IS_SEARCHABLE?: string, + * EDIT_FORM_LABEL?: string, + * LIST_COLUMN_LABEL?: string, + * LIST_FILTER_LABEL?: string, + * ERROR_MESSAGE?: string, + * HELP_MESSAGE?: string, + * LIST?: string, + * SETTINGS?: string, + * } $order + * @param array{ + * ID?: string, + * ENTITY_ID?: string, + * FIELD_NAME?: string, + * USER_TYPE_ID?: string, + * XML_ID?: string, + * SORT?: string, + * MULTIPLE?: string, + * MANDATORY?: string, + * SHOW_FILTER?: string, + * SHOW_IN_LIST?: string, + * EDIT_IN_LIST?: string, + * IS_SEARCHABLE?: string, + * EDIT_FORM_LABEL?: string, + * LIST_COLUMN_LABEL?: string, + * LIST_FILTER_LABEL?: string, + * ERROR_MESSAGE?: string, + * HELP_MESSAGE?: string, + * LIST?: string, + * SETTINGS?: string, + * } $filter + * + * @return ContactUserfieldsResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.contact.userfield.list', + 'https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_userfield_list.php', + 'Returns list of user custom fields for contacts by filter. Prints information about these fields, only identifier and without a title assigned to the field by the user. ' + )] + public function list(array $order, array $filter): ContactUserfieldsResult + { + return new ContactUserfieldsResult( + $this->core->call( + 'crm.contact.userfield.list', + [ + 'order' => $order, + 'filter' => $filter, + ] + ) + ); + } + + /** + * Creates a new user field for contacts. + * + * System limitation for field name - 20 characters. + * Prefix UF_CRM_is always added to the user field name. + * As a result, the actual name length - 13 characters. + * + * @param array{ + * FIELD_NAME?: string, + * USER_TYPE_ID?: string, + * XML_ID?: string, + * SORT?: string, + * MULTIPLE?: string, + * MANDATORY?: string, + * SHOW_FILTER?: string, + * SHOW_IN_LIST?: string, + * EDIT_IN_LIST?: string, + * IS_SEARCHABLE?: string, + * EDIT_FORM_LABEL?: string, + * LIST_COLUMN_LABEL?: string, + * LIST_FILTER_LABEL?: string, + * ERROR_MESSAGE?: string, + * HELP_MESSAGE?: string, + * LIST?: string, + * SETTINGS?: string, + * } $userfieldItemFields + * + * @return AddedItemResult + * @throws BaseException + * @throws TransportException + * @throws UserfieldNameIsTooLongException + * @link https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_userfield_add.php + * + */ + #[ApiEndpointMetadata( + 'crm.contact.userfield.add', + 'https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_userfield_add.php', + 'Creates a new user field for contacts.' + )] + public function add(array $userfieldItemFields): AddedItemResult + { + if (strlen($userfieldItemFields['FIELD_NAME']) > 13) { + throw new UserfieldNameIsTooLongException( + sprintf( + 'userfield name %s is too long %s, maximum length - 13 characters', + $userfieldItemFields['FIELD_NAME'], + strlen($userfieldItemFields['FIELD_NAME']) + ) + ); + } + + return new AddedItemResult( + $this->core->call( + 'crm.contact.userfield.add', + [ + 'fields' => $userfieldItemFields, + ] + ) + ); + } + + /** + * Deleted user field for contacts. + * + * @param int $userfieldId + * + * @return \Bitrix24\SDK\Core\Result\DeletedItemResult + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_userfield_delete.php + * + */ + #[ApiEndpointMetadata( + 'crm.contact.userfield.delete', + 'https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_userfield_delete.php', + 'Delete a user by Id' + )] + public function delete(int $userfieldId): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call( + 'crm.contact.userfield.delete', + [ + 'id' => $userfieldId, + ] + ) + ); + } + + /** + * Returns a user field for contacts by ID. + * + * @param int $contactUserfieldItemId + * + * @return ContactUserfieldResult + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_userfield_get.php + */ + #[ApiEndpointMetadata( + 'crm.contact.userfield.get', + 'https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_userfield_get.php', + 'Get a user by Id' + )] + public function get(int $contactUserfieldItemId): ContactUserfieldResult + { + return new ContactUserfieldResult( + $this->core->call( + 'crm.contact.userfield.get', + [ + 'id' => $contactUserfieldItemId, + ] + ) + ); + } + + /** + * Updates an existing user field for contacts. + * + * @param int $contactUserfieldItemId + * @param array $userfieldFieldsToUpdate + * + * @return UpdatedItemResult + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_userfield_update.php + */ + #[ApiEndpointMetadata( + 'crm.contact.userfield.update', + 'https://training.bitrix24.com/rest_help/crm/contacts/crm_contact_userfield_update.php', + 'Update a user by Id' + )] + public function update(int $contactUserfieldItemId, array $userfieldFieldsToUpdate): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call( + 'crm.contact.userfield.update', + [ + 'id' => $contactUserfieldItemId, + 'fields' => $userfieldFieldsToUpdate, + ] + ) + ); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/DealStageSemanticId.php b/src/Services/CRM/Deal/DealStageSemanticId.php new file mode 100644 index 00000000..f0bf7850 --- /dev/null +++ b/src/Services/CRM/Deal/DealStageSemanticId.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal; + +/** + * Status type identifier (STAGE_SEMANTIC_ID), line: + * "F": "(failed) - processed unsuccessfully", + * "S": "(success) - processed successfully", + * "P": "(processing) - deal in process" + */ +enum DealStageSemanticId: string +{ + case process = 'P'; + case success = 'S'; + case failure = 'F'; +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealCategoriesResult.php b/src/Services/CRM/Deal/Result/DealCategoriesResult.php new file mode 100644 index 00000000..92667c28 --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealCategoriesResult.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +/** + * Class DealCategoriesResult + * + * @package Bitrix24\SDK\Services\CRM\Deal\Result + */ +class DealCategoriesResult extends AbstractResult +{ + /** + * @return DealCategoryItemResult[] + * @throws BaseException + */ + public function getDealCategories(): array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $dealCategory) { + $res[] = new DealCategoryItemResult($dealCategory); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealCategoryItemResult.php b/src/Services/CRM/Deal/Result/DealCategoryItemResult.php new file mode 100644 index 00000000..02f430da --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealCategoryItemResult.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Result; + +use Bitrix24\SDK\Services\CRM\Common\Result\AbstractCrmItem; +use Carbon\CarbonImmutable; + +/** + * Class DealItemResult + * + * @property int $ID + * @property CarbonImmutable $CREATED_DATE + * @property string $NAME + * @property bool $IS_LOCKED + * @property int $SORT + */ +class DealCategoryItemResult extends AbstractCrmItem +{ +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealCategoryResult.php b/src/Services/CRM/Deal/Result/DealCategoryResult.php new file mode 100644 index 00000000..021f8420 --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealCategoryResult.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +/** + * Class DealCategoryResult + * + * @package Bitrix24\SDK\Services\CRM\Deal\Result + */ +class DealCategoryResult extends AbstractResult +{ + public function getDealCategoryFields(): DealCategoryItemResult + { + return new DealCategoryItemResult($this->getCoreResponse()->getResponseData()->getResult()); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealCategoryStageItemResult.php b/src/Services/CRM/Deal/Result/DealCategoryStageItemResult.php new file mode 100644 index 00000000..b8c198a6 --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealCategoryStageItemResult.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * Class DealCategoryStageItemResult + * + * @property string $NAME + * @property int $SORT + * @property string $STATUS_ID + */ +class DealCategoryStageItemResult extends AbstractItem +{ +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealCategoryStagesResult.php b/src/Services/CRM/Deal/Result/DealCategoryStagesResult.php new file mode 100644 index 00000000..0c421122 --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealCategoryStagesResult.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +/** + * Class DealCategoryStagesResult + * + * @property string $NAME + * @property int $SORT + * @property string $STATUS_ID + */ +class DealCategoryStagesResult extends AbstractResult +{ + /** + * @return DealCategoryStageItemResult[] + * @throws BaseException + */ + public function getDealCategoryStages(): array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $deal) { + $res[] = new DealCategoryStageItemResult($deal); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealCategoryStatusResult.php b/src/Services/CRM/Deal/Result/DealCategoryStatusResult.php new file mode 100644 index 00000000..0f9166f5 --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealCategoryStatusResult.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +/** + * Class DealCategoryStatusResult + * + * @package Bitrix24\SDK\Services\CRM\Deal\Result + */ +class DealCategoryStatusResult extends AbstractResult +{ + /** + * @return string + * @throws BaseException + */ + public function getDealCategoryTypeId(): string + { + return $this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealContactItemResult.php b/src/Services/CRM/Deal/Result/DealContactItemResult.php new file mode 100644 index 00000000..010ddc11 --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealContactItemResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * Class DealItemResult + * + * @property-read int $CONTACT_ID + * @property-read int $SORT + * @property-read int $ROLE_ID + * @property-read string $IS_PRIMARY + */ +class DealContactItemResult extends AbstractItem +{ +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealContactItemsResult.php b/src/Services/CRM/Deal/Result/DealContactItemsResult.php new file mode 100644 index 00000000..af24d8b1 --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealContactItemsResult.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +/** + * Class DealContactItemsResult + * + * @package Bitrix24\SDK\Services\CRM\Deal\Result + */ +class DealContactItemsResult extends AbstractResult +{ + /** + * @return DealContactItemResult[] + * @throws BaseException + */ + public function getDealContacts(): array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $dealContact) { + $res[] = new DealContactItemResult($dealContact); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealItemResult.php b/src/Services/CRM/Deal/Result/DealItemResult.php new file mode 100644 index 00000000..9cd56c1c --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealItemResult.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Result; + +use Bitrix24\SDK\Services\CRM\Common\Result\AbstractCrmItem; +use Carbon\CarbonImmutable; +use Money\Currency; + +/** + * Class DealItemResult + * @property-read int $ID + * @property-read string|null $TITLE deal title + * @property-read string|null $TYPE_ID + * @property-read string|null $CATEGORY_ID + * @property-read string|null $STAGE_ID + * @property-read DealSemanticStage|null $STAGE_SEMANTIC_ID + * @property-read bool|null $IS_NEW + * @property-read bool|null $IS_RECURRING + * @property-read string|null $PROBABILITY + * @property-read Currency|null $CURRENCY_ID + * @property-read string|null $OPPORTUNITY + * @property-read bool|null $IS_MANUAL_OPPORTUNITY + * @property-read string|null $TAX_VALUE + * @property-read int|null $LEAD_ID + * @property-read int|null $COMPANY_ID + * @property-read int|null $CONTACT_ID deprecated + * @property-read int|null $QUOTE_ID + * @property-read CarbonImmutable|null $BEGINDATE + * @property-read CarbonImmutable|null $CLOSEDATE + * @property-read bool|null $OPENED + * @property-read bool|null $CLOSED + * @property-read string|null $COMMENTS + * @property-read string|null $ADDITIONAL_INFO + * @property-read string|null $LOCATION_ID + * @property-read bool|null $IS_RETURN_CUSTOMER + * @property-read bool|null $IS_REPEATED_APPROACH + * @property-read int|null $SOURCE_ID + * @property-read string|null $SOURCE_DESCRIPTION + * @property-read string|null $ORIGINATOR_ID + * @property-read string|null $ORIGIN_ID + * @property-read string|null $UTM_SOURCE + * @property-read string|null $UTM_MEDIUM + * @property-read string|null $UTM_CAMPAIGN + * @property-read string|null $UTM_CONTENT + * @property-read string|null $UTM_TERM + */ +class DealItemResult extends AbstractCrmItem +{ + /** + * @param string $userfieldName + * + * @return mixed|null + * @throws \Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNotFoundException + */ + public function getUserfieldByFieldName(string $userfieldName) + { + return $this->getKeyWithUserfieldByFieldName($userfieldName); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealProductRowItemResult.php b/src/Services/CRM/Deal/Result/DealProductRowItemResult.php new file mode 100644 index 00000000..2d97529e --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealProductRowItemResult.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Result; +use Money\Money; +use MoneyPHP\Percentage\Percentage; + +use Bitrix24\SDK\Services\CRM\Common\Result\DiscountType; +use Carbon\CarbonImmutable; +use Bitrix24\SDK\Services\CRM\Common\Result\AbstractCrmItem; +/** + * @property-read int $ID + * @property-read int $OWNER_ID + * @property-read string $OWNER_TYPE + * @property-read int $PRODUCT_ID + * @property-read string $PRODUCT_NAME + * @property-read string|null $ORIGINAL_PRODUCT_NAME + * @property-read string|null $PRODUCT_DESCRIPTION + * @property-read Money $PRICE price with taxes and discounts + * @property-read Money $PRICE_EXCLUSIVE without taxes but with discounts + * @property-read Money $PRICE_NETTO without taxes and discounts + * @property-read Money $PRICE_BRUTTO without discounts but with taxes + * @property-read Money $PRICE_ACCOUNT formatted price + * @property-read string $QUANTITY + * @property-read DiscountType $DISCOUNT_TYPE_ID + * @property-read Percentage $DISCOUNT_RATE + * @property-read Money $DISCOUNT_SUM + * @property-read string $TAX_RATE + * @property-read bool $TAX_INCLUDED + * @property-read string $CUSTOMIZED + * @property-read int $MEASURE_CODE + * @property-read string $MEASURE_NAME + * @property-read int $SORT + * @property-read string|null $XML_ID + * @property-read int $TYPE + * @property-read int|null $STORE_ID + * @property-read int|null $RESERVE_ID + * @property-read CarbonImmutable|null $DATE_RESERVE_END + * @property-read int|null $RESERVE_QUANTITY + */ +class DealProductRowItemResult extends AbstractCrmItem +{ +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php b/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php new file mode 100644 index 00000000..f0b1a69f --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Response\Response; +use Bitrix24\SDK\Core\Result\AbstractResult; +use Money\Currency; + +/** + * Class DealProductRowItemsResult + * + * @package Bitrix24\SDK\Services\CRM\Deal\Result + */ +class DealProductRowItemsResult extends AbstractResult +{ + private Currency $currency; + + public function __construct(Response $coreResponse,Currency $currency) + { + parent::__construct($coreResponse); + $this->currency = $currency; + } + + /** + * @return DealProductRowItemResult[] + * @throws BaseException + */ + public function getProductRows(): array + { + $res = []; + if(!empty($this->getCoreResponse()->getResponseData()->getResult()['result']['rows'])) { + foreach ($this->getCoreResponse()->getResponseData()->getResult()['result']['rows'] as $productRow) { + $res[] = new DealProductRowItemResult($productRow, $this->currency); + } + } else { + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $productRow) { + $res[] = new DealProductRowItemResult($productRow, $this->currency); + } + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealResult.php b/src/Services/CRM/Deal/Result/DealResult.php new file mode 100644 index 00000000..d865b66d --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealResult.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +/** + * Class DealResult + * + * @package Bitrix24\SDK\Services\CRM\Deal\Result + */ +class DealResult extends AbstractResult +{ + public function deal(): DealItemResult + { + return new DealItemResult($this->getCoreResponse()->getResponseData()->getResult()); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealSemanticStage.php b/src/Services/CRM/Deal/Result/DealSemanticStage.php new file mode 100644 index 00000000..c913171c --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealSemanticStage.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Result; + +enum DealSemanticStage: string +{ + case underway = 'P'; + case successful = 'S'; + case failed = 'F'; +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealUserfieldItemResult.php b/src/Services/CRM/Deal/Result/DealUserfieldItemResult.php new file mode 100644 index 00000000..84642c84 --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealUserfieldItemResult.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Result; + +use Bitrix24\SDK\Services\CRM\Userfield\Result\AbstractUserfieldItemResult; + +class DealUserfieldItemResult extends AbstractUserfieldItemResult +{ +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealUserfieldResult.php b/src/Services/CRM/Deal/Result/DealUserfieldResult.php new file mode 100644 index 00000000..9a75284d --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealUserfieldResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class DealUserfieldResult extends AbstractResult +{ + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function userfieldItem(): DealUserfieldItemResult + { + 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 new file mode 100644 index 00000000..cc8c4701 --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealUserfieldsResult.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class DealUserfieldsResult extends AbstractResult +{ + /** + * @return \Bitrix24\SDK\Services\CRM\Deal\Result\DealUserfieldItemResult[] + * @throws BaseException + */ + public function getUserfields(): array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { + $res[] = new DealUserfieldItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Result/DealsResult.php b/src/Services/CRM/Deal/Result/DealsResult.php new file mode 100644 index 00000000..22fbd428 --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealsResult.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +/** + * Class DealsResult + * + * @package Bitrix24\SDK\Services\CRM\Deal\Result + */ +class DealsResult extends AbstractResult +{ + /** + * @return DealItemResult[] + * @throws BaseException + */ + public function getDeals(): array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $deal) { + $res[] = new DealItemResult($deal); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Service/Batch.php b/src/Services/CRM/Deal/Service/Batch.php new file mode 100644 index 00000000..62bc9134 --- /dev/null +++ b/src/Services/CRM/Deal/Service/Batch.php @@ -0,0 +1,276 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Service; + +use Bitrix24\SDK\Attributes\ApiBatchMethodMetadata; +use Bitrix24\SDK\Attributes\ApiBatchServiceMetadata; +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +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; + +#[ApiBatchServiceMetadata(new Scope(['crm']))] +class Batch +{ + protected BatchOperationsInterface $batch; + protected LoggerInterface $log; + + /** + * Batch constructor. + * + * @param BatchOperationsInterface $batch + * @param LoggerInterface $log + */ + public function __construct(BatchOperationsInterface $batch, LoggerInterface $log) + { + $this->batch = $batch; + $this->log = $log; + } + + /** + * Batch list method for deals + * + * @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?: int, + * CONTACT_IDS?: int[], + * 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|DealItemResult[] + * @throws BaseException + */ + #[ApiBatchMethodMetadata( + 'crm.deal.list', + 'https://training.bitrix24.com/rest_help/crm/deals/crm_deal_list.php', + 'Returns in batch mode a list of deals' + )] + 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.deal.list', $order, $filter, $select, $limit) as $key => $value) { + yield $key => new DealItemResult($value); + } + } + + /** + * Batch adding deals + * + * @param array $deals + * + * @return Generator + * @throws BaseException + */ + #[ApiBatchMethodMetadata( + 'crm.deal.add', + 'https://training.bitrix24.com/rest_help/crm/deals/crm_deal_add.php', + 'Add in batch mode a list of deals' + )] + public function add(array $deals): Generator + { + $items = []; + foreach ($deals as $contact) { + $items[] = [ + 'fields' => $contact, + ]; + } + foreach ($this->batch->addEntityItems('crm.deal.add', $items) as $key => $item) { + yield $key => new AddedItemBatchResult($item); + } + } + + /** + * Batch delete deals + * + * @param int[] $dealId + * + * @return Generator + * @throws BaseException + */ + #[ApiBatchMethodMetadata( + 'crm.deal.delete', + 'https://training.bitrix24.com/rest_help/crm/deals/crm_deal_delete.php', + 'Delete in batch mode a list of deals' + )] + public function delete(array $dealId): Generator + { + foreach ($this->batch->deleteEntityItems('crm.deal.delete', $dealId) as $key => $item) { + 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 BaseException + */ + #[ApiBatchMethodMetadata( + 'crm.deal.update', + 'https://training.bitrix24.com/rest_help/crm/deals/crm_deal_update.php', + 'Update in batch mode a list of deals' + )] + 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/Deal/Service/Deal.php b/src/Services/CRM/Deal/Service/Deal.php new file mode 100644 index 00000000..0f602bab --- /dev/null +++ b/src/Services/CRM/Deal/Service/Deal.php @@ -0,0 +1,340 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Service; + +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\AddedItemResult; +use Bitrix24\SDK\Core\Result\DeletedItemResult; +use Bitrix24\SDK\Core\Result\FieldsResult; +use Bitrix24\SDK\Core\Result\UpdatedItemResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\CRM\Deal\Result\DealResult; +use Bitrix24\SDK\Services\CRM\Deal\Result\DealsResult; +use Psr\Log\LoggerInterface; +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; + +#[ApiServiceMetadata(new Scope(['crm']))] +class Deal extends AbstractService +{ + public Batch $batch; + + /** + * Deal constructor. + * + * @param Batch $batch + * @param CoreInterface $core + * @param LoggerInterface $log + */ + public function __construct(Batch $batch, CoreInterface $core, LoggerInterface $log) + { + parent::__construct($core, $log); + $this->batch = $batch; + } + + /** + * add new deal + * + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_add.php + * + * @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, + * PROBABILITY?: string, + * CURRENCY_ID?: string, + * OPPORTUNITY?: string, + * IS_MANUAL_OPPORTUNITY?: string, + * TAX_VALUE?: string, + * LEAD_ID?: string, + * COMPANY_ID?: string, + * CONTACT_ID?: string, + * QUOTE_ID?: string, + * BEGINDATE?: string, + * CLOSEDATE?: string, + * OPENED?: string, + * CLOSED?: string, + * COMMENTS?: string, + * ADDITIONAL_INFO?: string, + * LOCATION_ID?: string, + * IS_RETURN_CUSTOMER?: string, + * IS_REPEATED_APPROACH?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string + * } $fields + * + * @param array{ + * REGISTER_SONET_EVENT?: string + * } $params + * + * @return AddedItemResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.deal.add', + 'https://training.bitrix24.com/rest_help/crm/deals/crm_deal_add.php', + 'Add new deal' + )] + public function add(array $fields, array $params = []): AddedItemResult + { + return new AddedItemResult( + $this->core->call( + 'crm.deal.add', + [ + 'fields' => $fields, + 'params' => $params, + ] + ) + ); + } + + /** + * Deletes the specified deal and all the associated objects. + * + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_delete.php + * + * @param int $id + * + * @return DeletedItemResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.deal.delete', + 'https://training.bitrix24.com/rest_help/crm/deals/crm_deal_delete.php', + 'Delete deal' + )] + public function delete(int $id): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call( + 'crm.deal.delete', + [ + 'id' => $id, + ] + ) + ); + } + + /** + * Returns the description of the deal fields, including user fields. + * + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_fields.php + * + * @return FieldsResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.deal.fields', + 'https://training.bitrix24.com/rest_help/crm/deals/crm_deal_fields.php', + 'Get fields of deal' + )] + public function fields(): FieldsResult + { + return new FieldsResult($this->core->call('crm.deal.fields')); + } + + /** + * Returns a deal by the deal ID. + * + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_get.php + * + * @param int $id + * + * @return DealResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.deal.fields', + 'https://training.bitrix24.com/rest_help/crm/deals/crm_deal_get.php', + 'Get deal by id' + )] + public function get(int $id): DealResult + { + return new DealResult($this->core->call('crm.deal.get', ['id' => $id])); + } + + /** + * Get list of deal items. + * + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_list.php + * + * @param array $order - order of deal items + * @param array $filter - filter array + * @param array $select = ['ID','TITLE','TYPE_ID','CATEGORY_ID','STAGE_ID','STAGE_SEMANTIC_ID','IS_NEW','IS_RECURRING','PROBABILITY', 'CURRENCY_ID', 'OPPORTUNITY','IS_MANUAL_OPPORTUNITY','TAX_VALUE','LEAD_ID','COMPANY_ID','CONTACT_ID','QUOTE_ID','BEGINDATE','CLOSEDATE','OPENED','CLOSED','COMMENTS','ADDITIONAL_INFO','LOCATION_ID','IS_RETURN_CUSTOMER','IS_REPEATED_APPROACH','SOURCE_ID','SOURCE_DESCRIPTION','ORIGINATOR_ID','ORIGIN_ID','UTM_SOURCE','UTM_MEDIUM','UTM_CAMPAIGN','UTM_CONTENT','UTM_TERM'] + * @param integer $startItem - entity number to start from (usually returned in 'next' field of previous 'crm.deal.list' API call) + * + * @throws BaseException + * @throws TransportException + * @return DealsResult + */ + #[ApiEndpointMetadata( + 'crm.deal.list', + 'https://training.bitrix24.com/rest_help/crm/deals/crm_deal_list.php', + 'Get deal list by filter' + )] + public function list(array $order, array $filter, array $select, int $startItem = 0): DealsResult + { + return new DealsResult( + $this->core->call( + 'crm.deal.list', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $startItem, + ] + ) + ); + } + + /** + * Updates the specified (existing) deal. + * + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_update.php + * + * @param int $id + * @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, + * PROBABILITY?: string, + * CURRENCY_ID?: string, + * OPPORTUNITY?: string, + * IS_MANUAL_OPPORTUNITY?: string, + * TAX_VALUE?: string, + * LEAD_ID?: string, + * COMPANY_ID?: string, + * CONTACT_ID?: string, + * QUOTE_ID?: string, + * BEGINDATE?: string, + * CLOSEDATE?: string, + * OPENED?: string, + * CLOSED?: string, + * COMMENTS?: string, + * ADDITIONAL_INFO?: string, + * LOCATION_ID?: string, + * IS_RETURN_CUSTOMER?: string, + * IS_REPEATED_APPROACH?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string + * } $fields + * + * @param array{ + * REGISTER_SONET_EVENT?: string + * } $params + * + * @return UpdatedItemResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.deal.update', + 'https://training.bitrix24.com/rest_help/crm/deals/crm_deal_update.php', + 'Update deal list by filter' + )] + public function update(int $id, array $fields, array $params = []): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call( + 'crm.deal.update', + [ + 'id' => $id, + 'fields' => $fields, + 'params' => $params, + ] + ) + ); + } + + /** + * Count deals by filter + * + * @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, + * PROBABILITY?: string, + * CURRENCY_ID?: string, + * OPPORTUNITY?: string, + * IS_MANUAL_OPPORTUNITY?: string, + * TAX_VALUE?: string, + * LEAD_ID?: string, + * COMPANY_ID?: string, + * CONTACT_ID?: string, + * QUOTE_ID?: string, + * BEGINDATE?: string, + * CLOSEDATE?: string, + * OPENED?: string, + * CLOSED?: string, + * COMMENTS?: string, + * ADDITIONAL_INFO?: string, + * LOCATION_ID?: string, + * IS_RETURN_CUSTOMER?: string, + * IS_REPEATED_APPROACH?: string, + * SOURCE_ID?: string, + * SOURCE_DESCRIPTION?: string, + * ORIGINATOR_ID?: string, + * ORIGIN_ID?: string, + * UTM_SOURCE?: string, + * UTM_MEDIUM?: string, + * UTM_CAMPAIGN?: string, + * UTM_CONTENT?: string, + * UTM_TERM?: string + * } $filter + * + * @return int + * @throws BaseException + * @throws 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/Deal/Service/DealCategory.php b/src/Services/CRM/Deal/Service/DealCategory.php new file mode 100644 index 00000000..da8908ae --- /dev/null +++ b/src/Services/CRM/Deal/Service/DealCategory.php @@ -0,0 +1,281 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\AddedItemResult; +use Bitrix24\SDK\Core\Result\DeletedItemResult; +use Bitrix24\SDK\Core\Result\FieldsResult; +use Bitrix24\SDK\Core\Result\UpdatedItemResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\CRM\Deal\Result\DealCategoriesResult; +use Bitrix24\SDK\Services\CRM\Deal\Result\DealCategoryResult; +use Bitrix24\SDK\Services\CRM\Deal\Result\DealCategoryStatusResult; + +#[ApiServiceMetadata(new Scope(['crm']))] +class DealCategory extends AbstractService +{ + /** + * Creates a new deal category. + * + * @link https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_add.php + * + * @param array{ + * ID?: int, + * CREATED_DATE?: string, + * NAME?: string, + * IS_LOCKED?: string, + * SORT?: int, + * } $fields + * + * @return AddedItemResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.dealcategory.add', + 'https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_add.php', + 'Add new deal category' + )] + public function add(array $fields): AddedItemResult + { + return new AddedItemResult( + $this->core->call( + 'crm.dealcategory.add', + [ + 'fields' => $fields, + ] + ) + ); + } + + /** + * Deletes a deal category. + * + * @link https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_delete.php + * + * @param int $categoryId + * + * @return DeletedItemResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.dealcategory.delete', + 'https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_delete.php', + 'Delete deal category' + )] + public function delete(int $categoryId): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call( + 'crm.dealcategory.delete', + [ + 'id' => $categoryId, + ] + ) + ); + } + + /** + * Returns field description for deal categories. + * + * @link https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_fields.php + * + * @return FieldsResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.dealcategory.fields', + 'https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_fields.php', + 'Returns field description for deal categories' + )] + public function fields(): FieldsResult + { + return new FieldsResult($this->core->call('crm.dealcategory.fields')); + } + + /** + * The method reads settings for general deal category + * + * @link https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_default_get.php + * @return DealCategoryResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.dealcategory.default.get', + 'https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_default_get.php', + 'he method reads settings for general deal category' + )] + public function getDefaultCategorySettings(): DealCategoryResult + { + return new DealCategoryResult($this->core->call('crm.dealcategory.default.get')); + } + + /** + * The method writes settings for general deal category. + * + * @link https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_default_set.php + * + * @param array{ + * NAME?: string, + * } $parameters + * + * @return UpdatedItemResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.dealcategory.default.set', + 'https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_default_set.php', + 'The method writes settings for general deal category.' + )] + public function setDefaultCategorySettings(array $parameters): UpdatedItemResult + { + return new UpdatedItemResult($this->core->call('crm.dealcategory.default.set', $parameters)); + } + + + /** + * Returns deal category by the ID + * + * @link https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_get.php + * + * @param int $categoryId + * + * @return DealCategoryResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.dealcategory.get', + 'https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_get.php', + 'Returns deal category by the ID' + )] + public function get(int $categoryId): DealCategoryResult + { + return new DealCategoryResult( + $this->core->call( + 'crm.dealcategory.get', + [ + 'id' => $categoryId, + ] + ) + ); + } + + /** + * Returns a list of deal categories by the filter. Is the implementation of list method for deal categories. + * + * @link https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_list.php + * + * @param array $order + * @param array $filter + * @param array $select + * @param int $start + * + * @return DealCategoriesResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.dealcategory.list', + 'https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_list.php', + 'Returns a list of deal categories by the filter.' + )] + public function list(array $order, array $filter, array $select, int $start): DealCategoriesResult + { + return new DealCategoriesResult( + $this->core->call( + 'crm.dealcategory.list', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $start, + ] + ) + ); + } + + /** + * Returns directory type ID for storage deal categories by the ID. + * + * @link https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_status.php + * + * @param int $categoryId + * + * @return DealCategoryStatusResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.dealcategory.list', + 'https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_status.php', + 'Returns directory type ID for storage deal categories by the ID.' + )] + public function getStatus(int $categoryId): DealCategoryStatusResult + { + return new DealCategoryStatusResult( + $this->core->call( + 'crm.dealcategory.status', + [ + 'id' => $categoryId, + ] + ) + ); + } + + /** + * Updates an existing category. + * + * @link https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_update.php + * + * @param int $categoryId + * @param array{ + * ID?: int, + * CREATED_DATE?: string, + * NAME?: string, + * IS_LOCKED?: string, + * SORT?: int, + * } $fields + * + * @return UpdatedItemResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.dealcategory.update', + 'https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_update.php', + 'Updates an existing category.' + )] + public function update(int $categoryId, array $fields): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call( + 'crm.dealcategory.update', + [ + 'id' => $categoryId, + 'fields' => $fields, + ] + ) + ); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Service/DealCategoryStage.php b/src/Services/CRM/Deal/Service/DealCategoryStage.php new file mode 100644 index 00000000..b9cb019c --- /dev/null +++ b/src/Services/CRM/Deal/Service/DealCategoryStage.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\CRM\Deal\Result\DealCategoryStagesResult; + +#[ApiServiceMetadata(new Scope(['crm']))] +class DealCategoryStage extends AbstractService +{ + /** + * @param int $categoryId Category ID. When ID = 0 or null is specified , returns "default" category statuses. When ID > 0 for nonexistent category , returns nothing. + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.dealcategory.stage.list', + 'https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_stage_list.php', + 'Returns list of deal stages for category by the ID. Equivalent to calling crm.status.list method with parameter ENTITY_ID equal to the result of calling crm.dealcategory.status method.' + )] + public function list(int $categoryId): DealCategoryStagesResult + { + return new DealCategoryStagesResult( + $this->core->call( + 'crm.dealcategory.stage.list', + [ + 'id' => $categoryId, + ] + ) + ); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Service/DealContact.php b/src/Services/CRM/Deal/Service/DealContact.php new file mode 100644 index 00000000..0e5eb038 --- /dev/null +++ b/src/Services/CRM/Deal/Service/DealContact.php @@ -0,0 +1,204 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\AddedItemResult; +use Bitrix24\SDK\Core\Result\DeletedItemResult; +use Bitrix24\SDK\Core\Result\FieldsResult; +use Bitrix24\SDK\Core\Result\UpdatedItemResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\CRM\Deal\Result\DealContactItemsResult; + +#[ApiServiceMetadata(new Scope(['crm']))] +class DealContact extends AbstractService +{ + /** + * Adds contact to specified deal. + * + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_contact_add.php + * + * @param int $dealId + * @param int $contactId + * @param bool $isPrimary + * @param int $sort + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.deal.contact.add', + 'https://training.bitrix24.com/rest_help/crm/category/crm_dealcategory_stage_list.php', + 'Adds contact to specified deal.' + )] + public function add(int $dealId, int $contactId, bool $isPrimary, int $sort = 100): AddedItemResult + { + return new AddedItemResult( + $this->core->call( + 'crm.deal.contact.add', + [ + 'id' => $dealId, + 'fields' => [ + 'CONTACT_ID' => $contactId, + 'IS_PRIMARY' => $isPrimary, + 'SORT' => $sort, + ], + ] + ) + ); + } + + /** + * Returns field descriptions for the deal-contact link used by methods of family crm.deal.contact.* + * + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_contact_fields.php + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.deal.contact.fields', + 'https://training.bitrix24.com/rest_help/crm/deals/crm_deal_contact_fields.php', + 'Returns field descriptions for the deal-contact link used by methods of family crm.deal.contact.*' + )] + public function fields(): FieldsResult + { + return new FieldsResult($this->core->call('crm.deal.contact.fields')); + } + + /** + * Returns a set of contacts, associated with the specified deal. + * + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_contact_items_get.php + * + * @param int $dealId + * + * @return DealContactItemsResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.deal.contact.items.get', + 'https://training.bitrix24.com/rest_help/crm/deals/crm_deal_contact_items_get.php', + 'Returns a set of contacts, associated with the specified deal.' + )] + public function itemsGet(int $dealId): DealContactItemsResult + { + return new DealContactItemsResult( + $this->core->call( + 'crm.deal.contact.items.get', + [ + 'id' => $dealId, + ] + ) + ); + } + + /** + * Clears a set of contacts, associated with the specified deal. + * + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_contact_items_delete.php + * + * @param int $dealId + * + * @return DeletedItemResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.deal.contact.items.delete', + 'https://training.bitrix24.com/rest_help/crm/deals/crm_deal_contact_items_delete.php', + 'Clears a set of contacts, associated with the specified deal.' + )] + public function itemsDelete(int $dealId): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call( + 'crm.deal.contact.items.delete', + [ + 'id' => $dealId, + ] + ) + ); + } + + /** + * Set a set of contacts, associated with the specified seal. + * + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_contact_items_set.php + * + * @param int $dealId + * @param array $contactItems + * + * @return UpdatedItemResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.deal.contact.items.set', + 'https://training.bitrix24.com/rest_help/crm/deals/crm_deal_contact_items_set.php', + 'Set a set of contacts, associated with the specified seal.' + )] + public function itemsSet(int $dealId, array $contactItems): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call( + 'crm.deal.contact.items.set', + [ + 'id' => $dealId, + 'items' => $contactItems, + ] + ) + ); + } + + /** + * Deletes contact from a specified deal + * + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_contact_delete.php + * + * @param int $dealId + * @param int $contactId + * + * @return DeletedItemResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.deal.contact.delete', + 'https://training.bitrix24.com/rest_help/crm/deals/crm_deal_contact_items_set.php', + 'Deletes contact from a specified deal' + )] + public function delete(int $dealId, int $contactId): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call( + 'crm.deal.contact.delete', + [ + 'id' => $dealId, + 'fields' => [ + 'CONTACT_ID' => $contactId, + ], + ] + ) + ); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Service/DealProductRows.php b/src/Services/CRM/Deal/Service/DealProductRows.php new file mode 100644 index 00000000..ec6bf9ce --- /dev/null +++ b/src/Services/CRM/Deal/Service/DealProductRows.php @@ -0,0 +1,120 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\UpdatedItemResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\CRM\Deal\Result\DealProductRowItemsResult; +use Bitrix24\SDK\Services\CRM\Deal\Result\DealResult; +use Money\Currency; + +#[ApiServiceMetadata(new Scope(['crm']))] +class DealProductRows extends AbstractService +{ + /** + * Returns products inside the specified deal. + * + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_productrows_get.php + * + * @param int $dealId + * @param Currency|null $currency + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.deal.productrows.get', + 'https://training.bitrix24.com/rest_help/crm/deals/crm_deal_productrows_get.php', + 'Returns products inside the specified deal.' + )] + public function get(int $dealId, Currency $currency = null): DealProductRowItemsResult + { + if ($currency === null) { + $res = $this->core->call('batch', [ + 'halt' => 0, + 'cmd' => [ + 'deal' => sprintf('crm.deal.get?ID=%s', $dealId), + 'rows' => sprintf('crm.deal.productrows.get?ID=%s', $dealId) + ], + ]); + $data = $res->getResponseData()->getResult(); + $currency = new Currency($data['result']['deal']['CURRENCY_ID']); + return new DealProductRowItemsResult($res,$currency); + } + return new DealProductRowItemsResult( + $this->core->call( + 'crm.deal.productrows.get', + [ + 'id' => $dealId, + ] + ), + $currency + ); + } + + + /** + * Creates or updates product entries inside the specified deal. + * + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_productrows_set.php + * + * @param int $dealId + * @param array $productRows + * + * @return UpdatedItemResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.deal.productrows.set', + 'https://training.bitrix24.com/rest_help/crm/deals/crm_deal_productrows_set.php', + 'Creates or updates product entries inside the specified deal.' + )] + public function set(int $dealId, array $productRows): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call( + 'crm.deal.productrows.set', + [ + 'id' => $dealId, + 'rows' => $productRows, + ] + ) + ); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Deal/Service/DealUserfield.php b/src/Services/CRM/Deal/Service/DealUserfield.php new file mode 100644 index 00000000..03080ba2 --- /dev/null +++ b/src/Services/CRM/Deal/Service/DealUserfield.php @@ -0,0 +1,244 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Deal\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\AddedItemResult; +use Bitrix24\SDK\Core\Result\DeletedItemResult; +use Bitrix24\SDK\Core\Result\UpdatedItemResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\CRM\Deal\Result\DealUserfieldResult; +use Bitrix24\SDK\Services\CRM\Deal\Result\DealUserfieldsResult; +use Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNameIsTooLongException; +#[ApiServiceMetadata(new Scope(['crm']))] +class DealUserfield extends AbstractService +{ + /** + * Returns list of user deal fields by filter. + * + * @param array{ + * ID?: string, + * ENTITY_ID?: string, + * FIELD_NAME?: string, + * USER_TYPE_ID?: string, + * XML_ID?: string, + * SORT?: string, + * MULTIPLE?: string, + * MANDATORY?: string, + * SHOW_FILTER?: string, + * SHOW_IN_LIST?: string, + * EDIT_IN_LIST?: string, + * IS_SEARCHABLE?: string, + * EDIT_FORM_LABEL?: string, + * LIST_COLUMN_LABEL?: string, + * LIST_FILTER_LABEL?: string, + * ERROR_MESSAGE?: string, + * HELP_MESSAGE?: string, + * LIST?: string, + * SETTINGS?: string, + * } $order + * @param array{ + * ID?: string, + * ENTITY_ID?: string, + * FIELD_NAME?: string, + * USER_TYPE_ID?: string, + * XML_ID?: string, + * SORT?: string, + * MULTIPLE?: string, + * MANDATORY?: string, + * SHOW_FILTER?: string, + * SHOW_IN_LIST?: string, + * EDIT_IN_LIST?: string, + * IS_SEARCHABLE?: string, + * EDIT_FORM_LABEL?: string, + * LIST_COLUMN_LABEL?: string, + * LIST_FILTER_LABEL?: string, + * ERROR_MESSAGE?: string, + * HELP_MESSAGE?: string, + * LIST?: string, + * SETTINGS?: string, + * } $filter + * + * @return \Bitrix24\SDK\Services\CRM\Deal\Result\DealUserfieldsResult + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_userfield_list.php + */ + #[ApiEndpointMetadata( + 'crm.deal.userfield.list', + 'https://training.bitrix24.com/rest_help/crm/deals/crm_deal_userfield_list.php', + 'Returns list of user deal fields by filter.' + )] + public function list(array $order, array $filter): DealUserfieldsResult + { + return new DealUserfieldsResult( + $this->core->call( + 'crm.deal.userfield.list', + [ + 'order' => $order, + 'filter' => $filter, + ] + ) + ); + } + + /** + * Created new user field for deals. + * + * System limitation for field name - 20 characters. + * Prefix UF_CRM_is always added to the user field name. + * As a result, the actual name length - 13 characters. + * + * @param array{ + * FIELD_NAME?: string, + * USER_TYPE_ID?: string, + * XML_ID?: string, + * SORT?: string, + * MULTIPLE?: string, + * MANDATORY?: string, + * SHOW_FILTER?: string, + * SHOW_IN_LIST?: string, + * EDIT_IN_LIST?: string, + * IS_SEARCHABLE?: string, + * EDIT_FORM_LABEL?: string, + * LIST_COLUMN_LABEL?: string, + * LIST_FILTER_LABEL?: string, + * ERROR_MESSAGE?: string, + * HELP_MESSAGE?: string, + * LIST?: string, + * SETTINGS?: string, + * } $userfieldItemFields + * + * @return \Bitrix24\SDK\Core\Result\AddedItemResult + * @throws BaseException + * @throws TransportException + * @throws UserfieldNameIsTooLongException + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_userfield_add.php + * + */ + #[ApiEndpointMetadata( + 'crm.deal.userfield.add', + 'https://training.bitrix24.com/rest_help/crm/deals/crm_deal_userfield_add.php', + 'Created new user field for deals.' + )] + public function add(array $userfieldItemFields): AddedItemResult + { + if (strlen($userfieldItemFields['FIELD_NAME']) > 13) { + throw new UserfieldNameIsTooLongException( + sprintf( + 'userfield name %s is too long %s, maximum length - 13 characters', + $userfieldItemFields['FIELD_NAME'], + strlen($userfieldItemFields['FIELD_NAME']) + ) + ); + } + + return new AddedItemResult( + $this->core->call( + 'crm.deal.userfield.add', + [ + 'fields' => $userfieldItemFields, + ] + ) + ); + } + + /** + * Deleted userfield for deals + * + * @param int $userfieldId + * + * @return \Bitrix24\SDK\Core\Result\DeletedItemResult + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_userfield_delete.php + * + */ + #[ApiEndpointMetadata( + 'crm.deal.userfield.delete', + 'https://training.bitrix24.com/rest_help/crm/deals/crm_deal_userfield_delete.php', + 'Deleted userfield for deals' + )] + public function delete(int $userfieldId): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call( + 'crm.deal.userfield.delete', + [ + 'id' => $userfieldId, + ] + ) + ); + } + + /** + * Returns a userfield for deal by ID. + * + * @param int $userfieldItemId + * + * @return DealUserfieldResult + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_userfield_get.php + */ + #[ApiEndpointMetadata( + 'crm.deal.userfield.get', + 'https://training.bitrix24.com/rest_help/crm/deals/crm_deal_userfield_get.php', + 'Returns a userfield for deal by ID.' + )] + public function get(int $userfieldItemId): DealUserfieldResult + { + return new DealUserfieldResult( + $this->core->call( + 'crm.deal.userfield.get', + [ + 'id' => $userfieldItemId, + ] + ) + ); + } + + /** + * Updates an existing user field for deals. + * + * @param int $userfieldItemId + * @param array $userfieldFieldsToUpdate + * + * @return \Bitrix24\SDK\Core\Result\UpdatedItemResult + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_userfield_update.php + */ + #[ApiEndpointMetadata( + 'crm.deal.userfield.update', + 'https://training.bitrix24.com/rest_help/crm/deals/crm_deal_userfield_update.php', + 'Updates an existing user field for deals.' + )] + public function update(int $userfieldItemId, array $userfieldFieldsToUpdate): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call( + 'crm.deal.userfield.update', + [ + 'id' => $userfieldItemId, + 'fields' => $userfieldFieldsToUpdate, + ] + ) + ); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Duplicates/Result/DuplicateResult.php b/src/Services/CRM/Duplicates/Result/DuplicateResult.php new file mode 100644 index 00000000..3683f454 --- /dev/null +++ b/src/Services/CRM/Duplicates/Result/DuplicateResult.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Duplicates\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class DuplicateResult extends AbstractResult +{ + public function hasDuplicateContacts(): bool + { + if (!array_key_exists('CONTACT', $this->getCoreResponse()->getResponseData()->getResult())) { + return false; + } + + if (count($this->getCoreResponse()->getResponseData()->getResult()['CONTACT']) > 1) { + return true; + } + + return false; + } + + public function hasOneContact(): bool + { + if (!array_key_exists('CONTACT', $this->getCoreResponse()->getResponseData()->getResult())) { + return false; + } + + if (count($this->getCoreResponse()->getResponseData()->getResult()['CONTACT']) === 1) { + return true; + } + + return false; + } + + /** + * @return array + * @throws BaseException + */ + public function getContactsId(): array + { + if (!array_key_exists('CONTACT', $this->getCoreResponse()->getResponseData()->getResult())) { + return []; + } + + return $this->getCoreResponse()->getResponseData()->getResult()['CONTACT']; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Duplicates/Service/Duplicate.php b/src/Services/CRM/Duplicates/Service/Duplicate.php new file mode 100644 index 00000000..aaf4ea87 --- /dev/null +++ b/src/Services/CRM/Duplicates/Service/Duplicate.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Duplicates\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\CRM\Duplicates\Result\DuplicateResult; + +#[ApiServiceMetadata(new Scope(['crm']))] +class Duplicate extends AbstractService +{ + /** + * @param array $phones + * @param EntityType|null $entityType + * @return DuplicateResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.duplicate.findbycomm', + 'https://training.bitrix24.com/rest_help/crm/auxiliary/duplicates/crm.duplicate.findbycomm.php', + 'The method returns IDs for leads, contacts or companies that contain the specified phone numbers or e-mails.' + )] + public function findByPhone(array $phones, ?EntityType $entityType = null): mixed + { + return new DuplicateResult($this->core->call('crm.duplicate.findbycomm', + [ + 'type' => 'PHONE', + 'values' => $phones, + 'entity_type' => $entityType?->value + ])); + } + + /** + * @param array $emails + * @param EntityType|null $entityType + * @return DuplicateResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.duplicate.findbycomm', + 'https://training.bitrix24.com/rest_help/crm/auxiliary/duplicates/crm.duplicate.findbycomm.php', + 'The method returns IDs for leads, contacts or companies that contain the specified phone numbers or e-mails.' + )] + public function findByEmail(array $emails, ?EntityType $entityType = null): DuplicateResult + { + return new DuplicateResult($this->core->call('crm.duplicate.findbycomm', + [ + 'type' => 'EMAIL', + 'values' => $emails, + 'entity_type' => $entityType?->value + ])); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Duplicates/Service/EntityType.php b/src/Services/CRM/Duplicates/Service/EntityType.php new file mode 100644 index 00000000..a4165fa9 --- /dev/null +++ b/src/Services/CRM/Duplicates/Service/EntityType.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Duplicates\Service; + +enum EntityType: string +{ + case Lead = 'LEAD'; + case Contact = 'CONTACT'; + case Company = 'COMPANY'; +} \ No newline at end of file diff --git a/src/Services/CRM/Item/Result/ItemItemResult.php b/src/Services/CRM/Item/Result/ItemItemResult.php new file mode 100644 index 00000000..5ac66a75 --- /dev/null +++ b/src/Services/CRM/Item/Result/ItemItemResult.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Item\Result; + +use Bitrix24\SDK\Services\CRM\Common\Result\AbstractCrmItem; +use Carbon\CarbonImmutable; +use Money\Currency; + +/** + * @property-read int $id + * @property-read string $xmlId + * @property-read string $title + * @property-read int $createdBy + * @property-read int $updatedBy + * @property-read int $movedBy + * @property-read CarbonImmutable $createdTime + * @property-read CarbonImmutable $updatedTime + * @property-read CarbonImmutable $movedTime + * @property-read int $categoryId + * @property-read bool $opened + * @property-read string $previousStageId + * @property-read CarbonImmutable $begindate + * @property-read CarbonImmutable $closedate + * @property-read int $companyId + * @property-read int $contactId + * @property-read int $opportunity + * @property-read bool $isManualOpportunity + * @property-read int $taxValue + * @property-read Currency $currencyId + * @property-read int $opportunityAccount + * @property-read int $taxValueAccount + * @property-read Currency $accountCurrencyId + * @property-read int $mycompanyId + * @property-read string $sourceId + * @property-read string $sourceDescription + * @property-read int $webformId + * @property-read int $assignedById + * @property-read int $lastActivityBy + * @property-read CarbonImmutable $lastActivityTime + * @property-read string $utmSource + * @property-read string $utmMedium + * @property-read string $utmCampaign + * @property-read string $utmContent + * @property-read string $utmTerm + * @property-read array $observers + * @property-read array $contactIds + * @property-read int $entityTypeId + */ +class ItemItemResult extends AbstractCrmItem +{ +} \ No newline at end of file diff --git a/src/Services/CRM/Item/Result/ItemResult.php b/src/Services/CRM/Item/Result/ItemResult.php new file mode 100644 index 00000000..d89251cd --- /dev/null +++ b/src/Services/CRM/Item/Result/ItemResult.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Item\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class ItemResult extends AbstractResult +{ + public function item(): ItemItemResult + { + return new ItemItemResult($this->getCoreResponse()->getResponseData()->getResult()['item']); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Item/Result/ItemsResult.php b/src/Services/CRM/Item/Result/ItemsResult.php new file mode 100644 index 00000000..9943e0b0 --- /dev/null +++ b/src/Services/CRM/Item/Result/ItemsResult.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Item\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class ItemsResult extends AbstractResult +{ + /** + * @return ItemItemResult[] + * @throws BaseException + */ + public function getItems(): array + { + $items = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { + $items[] = new ItemItemResult($item); + } + + return $items; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Item/Service/Batch.php b/src/Services/CRM/Item/Service/Batch.php new file mode 100644 index 00000000..546765ab --- /dev/null +++ b/src/Services/CRM/Item/Service/Batch.php @@ -0,0 +1,90 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Item\Service; + +use Bitrix24\SDK\Attributes\ApiBatchMethodMetadata; +use Bitrix24\SDK\Attributes\ApiBatchServiceMetadata; +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\DeletedItemBatchResult; +use Bitrix24\SDK\Services\CRM\Item\Result\ItemItemResult; +use Generator; +use Psr\Log\LoggerInterface; + +#[ApiBatchServiceMetadata(new Scope(['crm']))] +class Batch +{ + protected BatchOperationsInterface $batch; + protected LoggerInterface $log; + + public function __construct(BatchOperationsInterface $batch, LoggerInterface $log) + { + $this->batch = $batch; + $this->log = $log; + } + + /** + * Batch list method for crm items + * + * @return Generator + * @throws BaseException + */ + #[ApiBatchMethodMetadata( + 'crm.item.list', + 'https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_list.php', + 'Method returns array with SPA items with entityTypeId.' + )] + public function list(int $entityTypeId, array $order, array $filter, array $select, ?int $limit = null): Generator + { + $this->log->debug( + 'batchList', + [ + 'entityTypeId' => $entityTypeId, + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'limit' => $limit, + ] + ); + foreach ($this->batch->getTraversableList('crm.item.list', $order, $filter, $select, $limit, ['entityTypeId' => $entityTypeId]) as $key => $value) { + yield $key => new ItemItemResult($value); + } + } + + /** + * Batch adding crm items + * + * @return Generator + * @throws BaseException + */ + #[ApiBatchMethodMetadata( + 'crm.item.add', + 'https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_add.php', + 'Method creates new SPA item with entityTypeId.' + )] + public function add(int $entityTypeId, array $items): Generator + { + $rawItems = []; + foreach ($items as $item) { + $rawItems[] = [ + 'entityTypeId' => $entityTypeId, + 'fields' => $item, + ]; + } + foreach ($this->batch->addEntityItems('crm.item.add', $rawItems) as $key => $item) { + yield $key => new ItemItemResult($item->getResult()['item']); + } + } +} \ No newline at end of file diff --git a/src/Services/CRM/Item/Service/Item.php b/src/Services/CRM/Item/Service/Item.php new file mode 100644 index 00000000..5425be81 --- /dev/null +++ b/src/Services/CRM/Item/Service/Item.php @@ -0,0 +1,201 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Item\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\DeletedItemResult; +use Bitrix24\SDK\Core\Result\FieldsResult; +use Bitrix24\SDK\Core\Result\UpdatedItemResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\CRM\Item\Result\ItemResult; +use Bitrix24\SDK\Services\CRM\Item\Result\ItemsResult; +use Psr\Log\LoggerInterface; + +#[ApiServiceMetadata(new Scope(['crm']))] +class Item extends AbstractService +{ + public Batch $batch; + + public function __construct(Batch $batch, CoreInterface $core, LoggerInterface $log) + { + parent::__construct($core, $log); + $this->batch = $batch; + } + + /** + * Method creates new SPA item with entityTypeId. + * + * @link https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_add.php + * + * + * @param int $entityTypeId + * @param array $fields + * @return ItemResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.item.add', + 'https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_add.php', + 'Method creates new SPA item with entityTypeId.' + )] + public function add(int $entityTypeId, array $fields): ItemResult + { + return new ItemResult( + $this->core->call( + 'crm.item.add', + [ + 'entityTypeId' => $entityTypeId, + 'fields' => $fields, + ] + ) + ); + } + + /** + * Deletes item with id for SPA with entityTypeId. + * + * @link https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_delete.php + * + * @param int $entityTypeId + * @param int $id + * + * @return DeletedItemResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.item.delete', + 'https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_delete.php', + 'Deletes item with id for SPA with entityTypeId.' + )] + public function delete(int $entityTypeId, int $id): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call( + 'crm.item.delete', ['entityTypeId' => $entityTypeId, 'id' => $id] + ) + ); + } + + /** + * Returns the fields data with entityTypeId. + * + * @link https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_fields.php + * + * @param int $entityTypeId + * @return FieldsResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.item.fields', + 'https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_fields.php', + 'Returns the fields data with entityTypeId.' + )] + public function fields(int $entityTypeId): FieldsResult + { + return new FieldsResult($this->core->call('crm.item.fields', ['entityTypeId' => $entityTypeId])); + } + + /** + * Returns item data with id for SPA with entityTypeId. + * + * @link https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_get.php + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.item.get', + 'https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_get.php', + 'Returns item data with id for SPA with entityTypeId.' + )] + public function get(int $entityTypeId, int $id): ItemResult + { + return new ItemResult($this->core->call('crm.item.get', ['entityTypeId' => $entityTypeId, 'id' => $id])); + } + + /** + * Returns array with SPA items with entityTypeId + * + * @link https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_list.php + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.item.list', + 'https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_list.php', + 'Returns array with SPA items with entityTypeId' + )] + public function list(int $entityTypeId, array $order, array $filter, array $select, int $startItem = 0): ItemsResult + { + return new ItemsResult( + $this->core->call( + 'crm.item.list', + [ + 'entityTypeId' => $entityTypeId, + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $startItem, + ] + ) + ); + } + + /** + * Updates the specified (existing) item. + * + * @link https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_update.php + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.item.update', + 'https://training.bitrix24.com/rest_help/crm/dynamic/methodscrmitem/crm_item_update.php', + 'Updates the specified (existing) item.' + )] + public function update(int $entityTypeId, int $id, array $fields): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call( + 'crm.item.update', + [ + 'entityTypeId' => $entityTypeId, + 'id' => $id, + 'fields' => $fields, + ] + ) + ); + } + + /** + * Count by filter + * + * @throws BaseException + * @throws TransportException + */ + public function countByFilter(int $entityTypeId, array $filter = []): int + { + return $this->list($entityTypeId, [], $filter, ['id'], 1)->getCoreResponse()->getResponseData()->getPagination()->getTotal(); + } +} \ 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..347ac45e --- /dev/null +++ b/src/Services/CRM/Lead/Result/LeadItemResult.php @@ -0,0 +1,94 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Lead\Result; + +use Bitrix24\SDK\Services\CRM\Common\Result\AbstractCrmItem; +use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\Email; +use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\InstantMessenger; +use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\Phone; +use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\Website; +use Carbon\CarbonImmutable; + +/** + * Class LeadItemResult + * + * @property-read int $ID + * @property-read string $TITLE + * @property-read string $HONORIFIC + * @property-read string $NAME + * @property-read string $SECOND_NAME + * @property-read string $LAST_NAME + * @property-read CarbonImmutable|null $BIRTHDATE + * @property-read string $COMPANY_TITLE + * @property-read string $SOURCE_ID + * @property-read string $SOURCE_DESCRIPTION + * @property-read string $STATUS_ID + * @property-read string $STATUS_DESCRIPTION + * @property-read string $STATUS_SEMANTIC_ID + * @property-read string $POST + * @property-read string $ADDRESS + * @property-read string $ADDRESS_2 + * @property-read string $ADDRESS_CITY + * @property-read string $ADDRESS_POSTAL_CODE + * @property-read string $ADDRESS_REGION + * @property-read string $ADDRESS_PROVINCE + * @property-read string $ADDRESS_COUNTRY + * @property-read string $ADDRESS_COUNTRY_CODE + * @property-read int $ADDRESS_LOC_ADDR_ID + * @property-read string $CURRENCY_ID + * @property-read string $OPPORTUNITY + * @property-read string $IS_MANUAL_OPPORTUNITY + * @property-read string $OPENED + * @property-read string $COMMENTS + * @property-read string $HAS_PHONE + * @property-read string $HAS_EMAIL + * @property-read string $HAS_IMOL + * @property-read string $ASSIGNED_BY_ID + * @property-read string $CREATED_BY_ID + * @property-read string $MODIFY_BY_ID + * @property-read string $MOVED_BY_ID + * @property-read string $DATE_CREATE + * @property-read string $DATE_MODIFY + * @property-read string $MOVED_TIME + * @property-read string $COMPANY_ID + * @property-read string $CONTACT_ID + * @property-read string $CONTACT_IDS + * @property-read string $IS_RETURN_CUSTOMER + * @property-read string $DATE_CLOSED + * @property-read string $ORIGINATOR_ID + * @property-read string $ORIGIN_ID + * @property-read string $UTM_SOURCE + * @property-read string $UTM_MEDIUM + * @property-read string $UTM_CAMPAIGN + * @property-read string $UTM_CONTENT + * @property-read string $UTM_TERM + * @property-read Phone[] $PHONE + * @property-read Email[] $EMAIL + * @property-read Website[] $WEB + * @property-read InstantMessenger[] $IM + * @property-read string $LINK + */ +class LeadItemResult extends AbstractCrmItem +{ + /** + * @param string $userfieldName + * + * @return mixed|null + * @throws \Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNotFoundException + */ + public function getUserfieldByFieldName(string $userfieldName) + { + return $this->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..7f4d0f86 --- /dev/null +++ b/src/Services/CRM/Lead/Result/LeadResult.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Lead\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +/** + * Class LeadResult + * + * @package Bitrix24\SDK\Services\CRM\Lead\Result + */ +class LeadResult extends AbstractResult +{ + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function lead(): LeadItemResult + { + return new LeadItemResult($this->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..203a5b54 --- /dev/null +++ b/src/Services/CRM/Lead/Result/LeadsResult.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Lead\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +/** + * Class LeadsResult + * + * @package Bitrix24\SDK\Services\CRM\Lead\Result + */ +class LeadsResult extends AbstractResult +{ + /** + * @return LeadItemResult[] + * @throws BaseException + */ + public function getLeads(): array + { + $items = []; + foreach ($this->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..7b6e546c --- /dev/null +++ b/src/Services/CRM/Lead/Service/Batch.php @@ -0,0 +1,249 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Lead\Service; + +use Bitrix24\SDK\Attributes\ApiBatchMethodMetadata; +use Bitrix24\SDK\Attributes\ApiBatchServiceMetadata; +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AddedItemBatchResult; +use Bitrix24\SDK\Core\Result\DeletedItemBatchResult; +use Bitrix24\SDK\Services\CRM\Deal\Result\DealItemResult; +use Generator; +use Psr\Log\LoggerInterface; + +#[ApiBatchServiceMetadata(new Scope(['crm']))] +class Batch +{ + protected BatchOperationsInterface $batch; + protected LoggerInterface $log; + + /** + * Batch constructor. + * + * @param BatchOperationsInterface $batch + * @param LoggerInterface $log + */ + public function __construct(BatchOperationsInterface $batch, LoggerInterface $log) + { + $this->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 + */ + #[ApiBatchMethodMetadata( + 'crm.lead.list', + 'https://training.bitrix24.com/rest_help/crm/leads/crm_lead_list.php', + 'Batch list method for leads' + )] + 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 + * @throws BaseException + */ + #[ApiBatchMethodMetadata( + 'crm.lead.add', + 'https://training.bitrix24.com/rest_help/crm/leads/crm_lead_add.php', + 'Batch adding leads' + )] + 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 + * @throws BaseException + */ + #[ApiBatchMethodMetadata( + 'crm.lead.delete', + 'https://training.bitrix24.com/rest_help/crm/leads/crm_lead_delete.php', + 'Batch delete leads' + )] + 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..02d9716c --- /dev/null +++ b/src/Services/CRM/Lead/Service/Lead.php @@ -0,0 +1,399 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Lead\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\AddedItemResult; +use Bitrix24\SDK\Core\Result\DeletedItemResult; +use Bitrix24\SDK\Core\Result\FieldsResult; +use Bitrix24\SDK\Core\Result\UpdatedItemResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\CRM\Lead\Result\LeadResult; +use Bitrix24\SDK\Services\CRM\Lead\Result\LeadsResult; +use Psr\Log\LoggerInterface; +#[ApiServiceMetadata(new Scope(['crm']))] +class Lead extends AbstractService +{ + public Batch $batch; + + /** + * Lead constructor. + * + * @param Batch $batch + * @param CoreInterface $core + * @param LoggerInterface $log + */ + public function __construct(Batch $batch, CoreInterface $core, LoggerInterface $log) + { + parent::__construct($core, $log); + $this->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 + */ + #[ApiEndpointMetadata( + 'crm.lead.add', + 'https://training.bitrix24.com/rest_help/crm/leads/crm_lead_add.php', + 'Method adds new lead' + )] + 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 + */ + #[ApiEndpointMetadata( + 'crm.lead.delete', + 'https://training.bitrix24.com/rest_help/crm/leads/crm_lead_delete.php', + 'Deletes the specified lead and all the associated objects.' + )] + 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 + */ + #[ApiEndpointMetadata( + 'crm.lead.fields', + 'https://training.bitrix24.com/rest_help/crm/leads/crm_lead_fields.php', + 'Returns the description of the lead fields, including user fields.' + )] + 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 + */ + #[ApiEndpointMetadata( + 'crm.lead.get', + 'https://training.bitrix24.com/rest_help/crm/leads/crm_lead_get.php', + 'Returns a lead by the lead ID.' + )] + 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 + */ + #[ApiEndpointMetadata( + 'crm.lead.list', + 'https://training.bitrix24.com/rest_help/crm/leads/crm_lead_list.php', + 'Get list of lead items.' + )] + 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 + */ + #[ApiEndpointMetadata( + 'crm.lead.update', + 'https://training.bitrix24.com/rest_help/crm/leads/crm_lead_update.php', + 'Updates the specified (existing) lead.' + )] + 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/ProductItemResult.php b/src/Services/CRM/Product/Result/ProductItemResult.php new file mode 100644 index 00000000..657621a0 --- /dev/null +++ b/src/Services/CRM/Product/Result/ProductItemResult.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Product\Result; + +use Bitrix24\SDK\Services\CRM\Common\Result\AbstractCrmItem; + +/** + * Class ProductItemResult + * + * @property-read int $ID + * @property-read int $CATALOG_ID + * @property-read string $PRICE + * @property-read string $CURRENCY_ID + * @property-read string $NAME + * @property-read string $CODE + * @property-read string $DESCRIPTION + * @property-read string $DESCRIPTION_TYPE + * @property-read string $ACTIVE + * @property-read int $SECTION_ID + * @property-read int $SORT + * @property-read int $VAT_ID + * @property-read string $VAT_INCLUDED + * @property-read int $MEASURE + * @property-read string $XML_ID + * @property-read string $PREVIEW_PICTURE + * @property-read string $DETAIL_PICTURE + * @property-read string $DATE_CREATE + * @property-read string $TIMESTAMP_X + * @property-read int $MODIFIED_BY + * @property-read int $CREATED_BY + */ +class ProductItemResult extends AbstractCrmItem +{ +} \ No newline at end of file diff --git a/src/Services/CRM/Product/Result/ProductResult.php b/src/Services/CRM/Product/Result/ProductResult.php new file mode 100644 index 00000000..5cd5457f --- /dev/null +++ b/src/Services/CRM/Product/Result/ProductResult.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Product\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class ProductResult extends AbstractResult +{ + public function product(): ProductItemResult + { + 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 new file mode 100644 index 00000000..da840990 --- /dev/null +++ b/src/Services/CRM/Product/Result/ProductsResult.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Product\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +/** + * Class DealsResult + * + * @package Bitrix24\SDK\Services\CRM\Product\Result + */ +class ProductsResult extends AbstractResult +{ + /** + * @return \Bitrix24\SDK\Services\CRM\Product\Result\ProductItemResult[] + * @throws BaseException + */ + public function getProducts(): array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { + $res[] = new ProductItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Product/Service/Batch.php b/src/Services/CRM/Product/Service/Batch.php new file mode 100644 index 00000000..c4f7ac88 --- /dev/null +++ b/src/Services/CRM/Product/Service/Batch.php @@ -0,0 +1,111 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Product\Service; + +use Bitrix24\SDK\Attributes\ApiBatchMethodMetadata; +use Bitrix24\SDK\Attributes\ApiBatchServiceMetadata; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AddedItemBatchResult; +use Bitrix24\SDK\Services\AbstractBatchService; +use Bitrix24\SDK\Services\CRM\Product\Result\ProductItemResult; +use Generator; + +#[ApiBatchServiceMetadata(new Scope(['crm']))] +class Batch extends AbstractBatchService +{ + /** + * batch product list method + * + * @param array{ + * ID?: string + * } $order + * + * @param array{ + * ID?: int + * } $filter + * @param array $select = ['ID','CATALOG_ID','PRICE','CURRENCY_ID','NAME','CODE','DESCRIPTION','DESCRIPTION_TYPE','ACTIVE','SECTION_ID','SORT','VAT_ID','VAT_INCLUDED','MEASURE','XML_ID','PREVIEW_PICTURE','DETAIL_PICTURE','DATE_CREATE','TIMESTAMP_X','MODIFIED_BY','CREATED_BY'] + * @param int|null $limit + * + * @return Generator + * @throws BaseException + */ + #[ApiBatchMethodMetadata( + 'crm.product.list', + 'https://training.bitrix24.com/rest_help/crm/products/crm_product_list.php', + 'batch product list method' + )] + 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.product.list', $order, $filter, $select, $limit) as $key => $value) { + yield $key => new ProductItemResult($value); + } + } + + /** + * Batch adding product + * + * @param array $products + * + * @return Generator + */ + #[ApiBatchMethodMetadata( + 'crm.product.add', + 'https://training.bitrix24.com/rest_help/crm/products/crm_product_add.php', + 'Batch adding product' + )] + public function add(array $products): Generator + { + $items = []; + foreach ($products as $product) { + $items[] = [ + 'fields' => $product, + ]; + } + foreach ($this->batch->addEntityItems('crm.product.add', $items) as $key => $item) { + yield $key => new AddedItemBatchResult($item); + } + } +} \ No newline at end of file diff --git a/src/Services/CRM/Product/Service/Product.php b/src/Services/CRM/Product/Service/Product.php new file mode 100644 index 00000000..bf027036 --- /dev/null +++ b/src/Services/CRM/Product/Service/Product.php @@ -0,0 +1,288 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Product\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\AddedItemResult; +use Bitrix24\SDK\Core\Result\DeletedItemResult; +use Bitrix24\SDK\Core\Result\FieldsResult; +use Bitrix24\SDK\Core\Result\UpdatedItemResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\CRM\Product\Result\ProductResult; +use Bitrix24\SDK\Services\CRM\Product\Result\ProductsResult; +use Psr\Log\LoggerInterface; + +#[ApiServiceMetadata(new Scope(['crm']))] +class Product extends AbstractService +{ + public Batch $batch; + + /** + * Product constructor. + * + * @param Batch $batch + * @param CoreInterface $core + * @param LoggerInterface $log + */ + public function __construct(Batch $batch, CoreInterface $core, LoggerInterface $log) + { + parent::__construct($core, $log); + $this->batch = $batch; + } + + /** + * Add new product + * + * @link https://training.bitrix24.com/rest_help/crm/products/crm_product_add.php + * + * @param array{ + * ID?: int, + * CATALOG_ID?: int, + * PRICE?: string, + * CURRENCY_ID?: string, + * NAME?: string, + * CODE?: string, + * DESCRIPTION?: string, + * DESCRIPTION_TYPE?: string, + * ACTIVE?: string, + * SECTION_ID?: int, + * SORT?: int, + * VAT_ID?: int, + * VAT_INCLUDED?: string, + * MEASURE?: int, + * XML_ID?: string, + * PREVIEW_PICTURE?: string, + * DETAIL_PICTURE?: string, + * DATE_CREATE?: string, + * TIMESTAMP_X?: string, + * MODIFIED_BY?: int, + * CREATED_BY?: int + * } $fields + * + * @return AddedItemResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.product.add', + 'https://training.bitrix24.com/rest_help/crm/products/crm_product_add.php', + 'Add new product' + )] + public function add(array $fields): AddedItemResult + { + return new AddedItemResult( + $this->core->call( + 'crm.product.add', + [ + 'fields' => $fields, + ] + ) + ); + } + + /** + * Delete product by id + * + * @link https://training.bitrix24.com/rest_help/crm/products/crm_product_delete.php + * + * @param int $productId + * + * @return DeletedItemResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.product.delete', + 'https://training.bitrix24.com/rest_help/crm/products/crm_product_delete.php', + 'Delete product by id' + )] + public function delete(int $productId): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call( + 'crm.product.delete', + [ + 'id' => $productId, + ] + ) + ); + } + + /** + * Returns a product by the product id. + * + * @link https://training.bitrix24.com/rest_help/crm/products/crm_product_get.php + * + * @param int $id + * + * @return ProductResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.product.get', + 'https://training.bitrix24.com/rest_help/crm/products/crm_product_get.php', + 'Returns a product by the product id.' + )] + public function get(int $id): ProductResult + { + return new ProductResult($this->core->call('crm.product.get', ['id' => $id])); + } + + /** + * Returns the description of the product fields, including user fields. + * + * @link https://training.bitrix24.com/rest_help/crm/products/crm_product_fields.php + * + * @return FieldsResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.product.fields', + 'https://training.bitrix24.com/rest_help/crm/products/crm_product_fields.php', + 'Returns the description of the product fields, including user fields.' + )] + public function fields(): FieldsResult + { + return new FieldsResult($this->core->call('crm.product.fields')); + } + + /** + * Get list of product items. + * + * @link https://training.bitrix24.com/rest_help/crm/products/crm_product_list.php + * + * @param array $order - order of product items + * @param array $filter - filter array + * @param array $select = ['ID','CATALOG_ID','PRICE','CURRENCY_ID','NAME','CODE','DESCRIPTION','DESCRIPTION_TYPE','ACTIVE','SECTION_ID','SORT','VAT_ID','VAT_INCLUDED','MEASURE','XML_ID','PREVIEW_PICTURE','DETAIL_PICTURE','DATE_CREATE','TIMESTAMP_X','MODIFIED_BY','CREATED_BY'] + * @param int $startItem - entity number to start from (usually returned in 'next' field of previous 'crm.product.list' API call) + * + * @return ProductsResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.product.list', + 'https://training.bitrix24.com/rest_help/crm/products/crm_product_list.php', + 'Get list of product items.' + )] + public function list(array $order, array $filter, array $select, int $startItem = 0): ProductsResult + { + return new ProductsResult( + $this->core->call( + 'crm.product.list', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => $startItem, + ] + ) + ); + } + + /** + * Updates the specified (existing) product. + * + * @link https://training.bitrix24.com/rest_help/crm/products/crm_product_update.php + * + * @param int $id + * @param array{ + * ID?: int, + * CATALOG_ID?: int, + * PRICE?: string, + * CURRENCY_ID?: string, + * NAME?: string, + * CODE?: string, + * DESCRIPTION?: string, + * DESCRIPTION_TYPE?: string, + * ACTIVE?: string, + * SECTION_ID?: int, + * SORT?: int, + * VAT_ID?: int, + * VAT_INCLUDED?: string, + * MEASURE?: int, + * XML_ID?: string, + * PREVIEW_PICTURE?: string, + * DETAIL_PICTURE?: string, + * DATE_CREATE?: string, + * TIMESTAMP_X?: string, + * MODIFIED_BY?: int, + * CREATED_BY?: int + * } $fields + * + * @return UpdatedItemResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.product.update', + 'https://training.bitrix24.com/rest_help/crm/products/crm_product_update.php', + 'Updates the specified (existing) product.' + )] + public function update(int $id, array $fields): UpdatedItemResult + { + return new UpdatedItemResult( + $this->core->call( + 'crm.product.update', + [ + 'id' => $id, + 'fields' => $fields, + ] + ) + ); + } + + /** + * Count products by filter + * + * @param array{ + * ID?: int, + * CATALOG_ID?: int, + * PRICE?: string, + * CURRENCY_ID?: string, + * NAME?: string, + * CODE?: string, + * DESCRIPTION?: string, + * DESCRIPTION_TYPE?: string, + * ACTIVE?: string, + * SECTION_ID?: int, + * SORT?: int, + * VAT_ID?: int, + * VAT_INCLUDED?: string, + * MEASURE?: int, + * XML_ID?: string, + * PREVIEW_PICTURE?: string, + * DETAIL_PICTURE?: string, + * DATE_CREATE?: string, + * TIMESTAMP_X?: string, + * MODIFIED_BY?: int, + * CREATED_BY?: int + * } $filter + * + * @return int + * @throws BaseException + * @throws 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/Settings/Result/SettingsModeResult.php b/src/Services/CRM/Settings/Result/SettingsModeResult.php new file mode 100644 index 00000000..cc8642d0 --- /dev/null +++ b/src/Services/CRM/Settings/Result/SettingsModeResult.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Settings\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +/** + * Class SettingsModeResult + * + * @package Bitrix24\SDK\Services\CRM\Settings\Result + */ +class SettingsModeResult extends AbstractResult +{ + public function getModeId(): int + { + return $this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Settings/Service/Settings.php b/src/Services/CRM/Settings/Service/Settings.php new file mode 100644 index 00000000..a99a7e1d --- /dev/null +++ b/src/Services/CRM/Settings/Service/Settings.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Settings\Service; + +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\CRM\Settings\Result\SettingsModeResult; +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; + +#[ApiServiceMetadata(new Scope(['crm']))] +class Settings extends AbstractService +{ + /** + * @return SettingsModeResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.settings.mode.get', + 'https://training.bitrix24.com/rest_help/crm/mode/crm_settings_mode_get.php', + 'The method returns current settings for CRM mode' + )] + public function modeGet(): SettingsModeResult + { + return new SettingsModeResult($this->core->call('crm.settings.mode.get')); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Userfield/Exceptions/UserfieldNameIsTooLongException.php b/src/Services/CRM/Userfield/Exceptions/UserfieldNameIsTooLongException.php new file mode 100644 index 00000000..13d2fc5a --- /dev/null +++ b/src/Services/CRM/Userfield/Exceptions/UserfieldNameIsTooLongException.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Userfield\Exceptions; + +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; + +class UserfieldNameIsTooLongException extends InvalidArgumentException +{ +} diff --git a/src/Services/CRM/Userfield/Exceptions/UserfieldNotFoundException.php b/src/Services/CRM/Userfield/Exceptions/UserfieldNotFoundException.php new file mode 100644 index 00000000..6205306f --- /dev/null +++ b/src/Services/CRM/Userfield/Exceptions/UserfieldNotFoundException.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Userfield\Exceptions; + +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; + +class UserfieldNotFoundException extends InvalidArgumentException +{ +} \ No newline at end of file diff --git a/src/Services/CRM/Userfield/Result/AbstractUserfieldItemResult.php b/src/Services/CRM/Userfield/Result/AbstractUserfieldItemResult.php new file mode 100644 index 00000000..44416332 --- /dev/null +++ b/src/Services/CRM/Userfield/Result/AbstractUserfieldItemResult.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Userfield\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read string $ID + * @property-read string $ENTITY_ID + * @property-read string $FIELD_NAME + * @property-read string $USER_TYPE_ID + * @property-read string $XML_ID + * @property-read string $SORT + * @property-read string $MULTIPLE + * @property-read string $MANDATORY + * @property-read string $SHOW_FILTER + * @property-read string $SHOW_IN_LIST + * @property-read string $EDIT_IN_LIST + * @property-read string $IS_SEARCHABLE + * @property-read array $EDIT_FORM_LABEL + * @property-read array $LIST_COLUMN_LABEL + * @property-read array $LIST_FILTER_LABEL + * @property-read string $ERROR_MESSAGE + * @property-read string $HELP_MESSAGE + * @property-read array $LIST + * @property-read array $SETTINGS + */ +class AbstractUserfieldItemResult extends AbstractItem +{ + //crm userfield name prefix UF_CRM_ + private const CRM_USERFIELD_PREFIX_LENGTH = 7; + + /** + * get userfield name without prefix UF_CRM_ + * + * @return string + */ + public function getOriginalFieldName(): string + { + return substr($this->FIELD_NAME, self::CRM_USERFIELD_PREFIX_LENGTH); + } +} \ No newline at end of file diff --git a/src/Services/CRM/Userfield/Result/UserfieldTypeItemResult.php b/src/Services/CRM/Userfield/Result/UserfieldTypeItemResult.php new file mode 100644 index 00000000..5e697627 --- /dev/null +++ b/src/Services/CRM/Userfield/Result/UserfieldTypeItemResult.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Userfield\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read string $ID + * @property-read string $title + */ +class UserfieldTypeItemResult extends AbstractItem +{ +} \ No newline at end of file diff --git a/src/Services/CRM/Userfield/Result/UserfieldTypesResult.php b/src/Services/CRM/Userfield/Result/UserfieldTypesResult.php new file mode 100644 index 00000000..2742b2f7 --- /dev/null +++ b/src/Services/CRM/Userfield/Result/UserfieldTypesResult.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Userfield\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class UserfieldTypesResult extends AbstractResult +{ + /** + * @return \Bitrix24\SDK\Services\CRM\Userfield\Result\UserfieldTypeItemResult[] + * @throws BaseException + */ + public function getTypes(): array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { + $res[] = new UserfieldTypeItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/CRM/Userfield/Service/Userfield.php b/src/Services/CRM/Userfield/Service/Userfield.php new file mode 100644 index 00000000..e855723b --- /dev/null +++ b/src/Services/CRM/Userfield/Service/Userfield.php @@ -0,0 +1,101 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\CRM\Userfield\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\FieldsResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\CRM\Userfield\Result\UserfieldTypesResult; +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Credentials\Scope; + +#[ApiServiceMetadata(new Scope(['crm']))] +class Userfield extends AbstractService +{ + /** + * Returns list of user field types. + * + * @link https://training.bitrix24.com/rest_help/crm/userfields/crm_userfield_types.php + * @return UserfieldTypesResult + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'crm.userfield.types', + 'https://training.bitrix24.com/rest_help/crm/userfields/crm_userfield_types.php', + 'Returns list of user field types.' + )] + public function types(): UserfieldTypesResult + { + return new UserfieldTypesResult($this->core->call('crm.userfield.types')); + } + + /** + * Returns field description for user fields. + * + * @link https://training.bitrix24.com/rest_help/crm/userfields/crm_userfield_fields.php + * @return \Bitrix24\SDK\Core\Result\FieldsResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + #[ApiEndpointMetadata( + 'crm.userfield.fields', + 'https://training.bitrix24.com/rest_help/crm/userfields/crm_userfield_fields.php', + 'Returns field description for user fields.' + )] + public function fields(): FieldsResult + { + return new FieldsResult($this->core->call('crm.userfield.fields')); + } + + /** + * Returns field description for "enumeration" user field type (list). + * + * @link https://training.bitrix24.com/rest_help/crm/userfields/crm_userfield_enumeration_fields.php + * @return \Bitrix24\SDK\Core\Result\FieldsResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + #[ApiEndpointMetadata( + 'crm.userfield.fields', + 'https://training.bitrix24.com/rest_help/crm/userfields/crm_userfield_fields.php', + 'Returns field description for user fields.' + )] + public function enumerationFields(): FieldsResult + { + return new FieldsResult($this->core->call('crm.userfield.enumeration.fields')); + } + + /** + * Returns settings field description for user field type. + * + * @link https://training.bitrix24.com/rest_help/crm/userfields/crm_userfield_settings_fields.php + * + * @param string $userfieldTypeId + * + * @return \Bitrix24\SDK\Core\Result\FieldsResult + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function settingsFields(string $userfieldTypeId): FieldsResult + { + return new FieldsResult( + $this->core->call('crm.userfield.settings.fields', [ + 'type' => $userfieldTypeId, + ]) + ); + } +} \ No newline at end of file diff --git a/src/Services/Catalog/Catalog/Result/CatalogItemResult.php b/src/Services/Catalog/Catalog/Result/CatalogItemResult.php new file mode 100644 index 00000000..e62fc7cb --- /dev/null +++ b/src/Services/Catalog/Catalog/Result/CatalogItemResult.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Catalog\Catalog\Result; + +use Bitrix24\SDK\Services\Catalog\Common\Result\AbstractCatalogItem; + +/** + * @property-read int $iblockId + * @property-read int $iblockTypeId + * @property-read int $id + * @property-read string $lid + * @property-read string $name + * @property-read int $productIblockId + * @property-read int $skuPropertyId + * @property-read bool $subscription + * @property-read int $vatId + * @property-read bool $yandexExport + */ +class CatalogItemResult extends AbstractCatalogItem +{ +} \ No newline at end of file diff --git a/src/Services/Catalog/Catalog/Result/CatalogResult.php b/src/Services/Catalog/Catalog/Result/CatalogResult.php new file mode 100644 index 00000000..aa468aa8 --- /dev/null +++ b/src/Services/Catalog/Catalog/Result/CatalogResult.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Catalog\Catalog\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class CatalogResult extends AbstractResult +{ + public function catalog(): CatalogItemResult + { + return new CatalogItemResult($this->getCoreResponse()->getResponseData()->getResult()['catalog']); + } +} \ No newline at end of file diff --git a/src/Services/Catalog/Catalog/Result/CatalogsResult.php b/src/Services/Catalog/Catalog/Result/CatalogsResult.php new file mode 100644 index 00000000..add5f259 --- /dev/null +++ b/src/Services/Catalog/Catalog/Result/CatalogsResult.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Catalog\Catalog\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; +use Bitrix24\SDK\Services\Catalog\Product\Result\ProductItemResult; + +class CatalogsResult extends AbstractResult +{ + /** + * @return ProductItemResult[] + * @throws BaseException + */ + public function getCatalogs(): array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult()['catalogs'] as $product) { + $res[] = new ProductItemResult($product); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/Catalog/Catalog/Service/Catalog.php b/src/Services/Catalog/Catalog/Service/Catalog.php new file mode 100644 index 00000000..d9cb55fe --- /dev/null +++ b/src/Services/Catalog/Catalog/Service/Catalog.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Catalog\Catalog\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\FieldsResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Catalog\Catalog\Result\CatalogResult; +use Bitrix24\SDK\Services\Catalog\Catalog\Result\CatalogsResult; + +#[ApiServiceMetadata(new Scope(['catalog']))] +class Catalog extends AbstractService +{ + /** + * The method gets field values of commercial catalog by ID. + * + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/catalog/catalog/catalog_catalog_get.php + */ + #[ApiEndpointMetadata( + 'catalog.catalog.get', + 'https://training.bitrix24.com/rest_help/catalog/catalog/catalog_catalog_get.php', + 'The method gets field values of commercial catalog by ID.' + )] + public function get(int $catalogId): CatalogResult + { + return new CatalogResult($this->core->call('catalog.catalog.get', ['id' => $catalogId])); + } + + /** + * The method gets field value of commercial catalog product list + * + * @see https://training.bitrix24.com/rest_help/catalog/catalog/catalog_catalog_list.php + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'catalog.catalog.list', + 'https://training.bitrix24.com/rest_help/catalog/catalog/catalog_catalog_list.php', + 'The method gets field value of commercial catalog product list' + )] + public function list(array $select, array $filter, array $order, int $start): CatalogsResult + { + return new CatalogsResult($this->core->call('catalog.catalog.list', [ + 'select' => $select, + 'filter' => $filter, + 'order' => $order, + 'start' => $start + ])); + } + + /** + * Retrieves the fields for the catalog. + * + * @return FieldsResult Returns an instance of FieldsResult. + * @throws BaseException Throws a BaseException if there is an error in the core call. + * @throws TransportException Throws a TransportException if there is an error in the transport process. + * @see https://training.bitrix24.com/rest_help/catalog/catalog/catalog_catalog_getfields.php + */ + #[ApiEndpointMetadata( + 'catalog.catalog.getFields', + 'https://training.bitrix24.com/rest_help/catalog/catalog/catalog_catalog_getfields.php', + 'Retrieves the fields for the catalog.' + )] + public function fields(): FieldsResult + { + return new FieldsResult($this->core->call('catalog.catalog.getFields')); + } +} \ No newline at end of file diff --git a/src/Services/Catalog/CatalogServiceBuilder.php b/src/Services/Catalog/CatalogServiceBuilder.php new file mode 100644 index 00000000..b41933db --- /dev/null +++ b/src/Services/Catalog/CatalogServiceBuilder.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Catalog; + +use Bitrix24\SDK\Services\AbstractServiceBuilder; +use Bitrix24\SDK\Services\Catalog; + +class CatalogServiceBuilder extends AbstractServiceBuilder +{ + public function product(): Catalog\Product\Service\Product + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Catalog\Product\Service\Product( + new Catalog\Product\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + + public function catalog(): Catalog\Catalog\Service\Catalog + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Catalog\Catalog\Service\Catalog( + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } +} \ No newline at end of file diff --git a/src/Services/Catalog/Common/ProductType.php b/src/Services/Catalog/Common/ProductType.php new file mode 100644 index 00000000..0bf8ef09 --- /dev/null +++ b/src/Services/Catalog/Common/ProductType.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Catalog\Common; + +enum ProductType: int +{ + case simple = 1; + case bundle = 2; + case SKU = 3; + case productOffer = 4; + case genericOffer = 5; +} \ No newline at end of file diff --git a/src/Services/Catalog/Common/Result/AbstractCatalogItem.php b/src/Services/Catalog/Common/Result/AbstractCatalogItem.php new file mode 100644 index 00000000..7b6da5fd --- /dev/null +++ b/src/Services/Catalog/Common/Result/AbstractCatalogItem.php @@ -0,0 +1,112 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Catalog\Common\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; +use Bitrix24\SDK\Services\Catalog\Common\ProductType; +use Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNotFoundException; +use Carbon\CarbonImmutable; +use Money\Currency; + +abstract class AbstractCatalogItem extends AbstractItem +{ + private const CRM_USERFIELD_PREFIX = 'UF_CRM_'; + + private Currency $currency; + + public function __construct(array $data, Currency $currency = null) + { + parent::__construct($data); + if ($currency instanceof Currency) { + $this->currency = $currency; + } + } + + /** + * @param int|string $offset + * + * @return bool|CarbonImmutable|int|mixed|null + */ + + public function __get($offset) + { + switch ($offset) { + case 'active': + case 'available': + case 'bundle': + return $this->data[$offset] === 'Y'; + case 'barcodeMulti': + case 'canBuyZero': + if ($this->data[$offset] !== null) { + return $this->data[$offset] === 'Y'; + } + + return null; + case 'code': + case 'detailText': + case 'detailTextType': + case 'name': + case 'previewText': + case 'previewTextType': + case 'xmlId': + return (string)$this->data[$offset]; + case 'createdBy': + case 'iblockId': + case 'iblockSectionId': + case 'id': + case 'modifiedBy': + case 'sort': + case 'height': + case 'length': + if ($this->data[$offset] !== '' && $this->data[$offset] !== null) { + return (int)$this->data[$offset]; + } + + break; + case 'dateActiveFrom': + case 'dateActiveTo': + case 'dateCreate': + case 'timestampX': + if ($this->data[$offset] !== '') { + return CarbonImmutable::createFromFormat(DATE_ATOM, $this->data[$offset]); + } + + return null; + case 'type': + return ProductType::from($this->data[$offset]); + } + + return $this->data[$offset] ?? null; + } + + /** + * get userfield by field name + * + * + * @return mixed|null + * @throws UserfieldNotFoundException + */ + protected function getKeyWithUserfieldByFieldName(string $fieldName) + { + if (!str_starts_with($fieldName, self::CRM_USERFIELD_PREFIX)) { + $fieldName = self::CRM_USERFIELD_PREFIX . $fieldName; + } + + if (!$this->isKeyExists($fieldName)) { + throw new UserfieldNotFoundException(sprintf('crm userfield not found by field name %s', $fieldName)); + } + + return $this->$fieldName; + } +} \ No newline at end of file diff --git a/src/Services/Catalog/Product/Result/ProductItemResult.php b/src/Services/Catalog/Product/Result/ProductItemResult.php new file mode 100644 index 00000000..c576d9b7 --- /dev/null +++ b/src/Services/Catalog/Product/Result/ProductItemResult.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Catalog\Product\Result; + +use Bitrix24\SDK\Services\Catalog\Common\ProductType; +use Bitrix24\SDK\Services\Catalog\Common\Result\AbstractCatalogItem; +use Carbon\CarbonImmutable; +use Money\Currency; +use Money\Money; + +/** + * @property-read bool $active Active + * @property-read bool $available Availability, read only + * @property-read bool $bundle Bundle + * @property-read ?bool $barcodeMulti + * @property-read ?bool $canBuyZero Option: Make out-of-stock items available for purchase + * @property-read string $code Symbolic code + * @property-read int $createdBy Created by (id) + * @property-read CarbonImmutable|null $dateActiveFrom Active from + * @property-read CarbonImmutable|null $dateActiveTo Active till + * @property-read CarbonImmutable $dateCreate Date created + * @property-read array|null $detailPicture + * @property-read string $detailText + * @property-read string $detailTextType + * @property-read int $id + * @property-read int $iblockId + * @property-read int $iblockSectionId + * @property-read int $modifiedBy + * @property-read ?int $height + * @property-read ?int $length + * @property-read mixed $measure + * @property-read string $name + * @property-read array|null $previewPicture + * @property-read string $previewText + * @property-read string $previewTextType + * @property-read ?Currency $purchasingCurrency + * @property-read ?Money $purchasingPrice + * @property-read CarbonImmutable $timestampX + * @property-read ProductType $type + * @property-read string $xmlId + */ +class ProductItemResult extends AbstractCatalogItem +{ +} \ No newline at end of file diff --git a/src/Services/Catalog/Product/Result/ProductResult.php b/src/Services/Catalog/Product/Result/ProductResult.php new file mode 100644 index 00000000..2751fda8 --- /dev/null +++ b/src/Services/Catalog/Product/Result/ProductResult.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Catalog\Product\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class ProductResult extends AbstractResult +{ + public function product(): ProductItemResult + { + if (array_key_exists('element', $this->getCoreResponse()->getResponseData()->getResult())) { + // fix for catalog.product.add + return new ProductItemResult($this->getCoreResponse()->getResponseData()->getResult()['element']); + } + + return new ProductItemResult($this->getCoreResponse()->getResponseData()->getResult()['product']); + } +} \ No newline at end of file diff --git a/src/Services/Catalog/Product/Result/ProductsResult.php b/src/Services/Catalog/Product/Result/ProductsResult.php new file mode 100644 index 00000000..aa644fa3 --- /dev/null +++ b/src/Services/Catalog/Product/Result/ProductsResult.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Catalog\Product\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class ProductsResult extends AbstractResult +{ + /** + * @return ProductItemResult[] + * @throws BaseException + */ + public function getProducts(): array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult()['products'] as $product) { + $res[] = new ProductItemResult($product); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/Catalog/Product/Service/Batch.php b/src/Services/Catalog/Product/Service/Batch.php new file mode 100644 index 00000000..45dddcb7 --- /dev/null +++ b/src/Services/Catalog/Product/Service/Batch.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Catalog\Product\Service; + +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +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 Generator; +use Psr\Log\LoggerInterface; + +readonly class Batch +{ + public function __construct( + protected BatchOperationsInterface $batch, + protected LoggerInterface $log) + { + } +} \ No newline at end of file diff --git a/src/Services/Catalog/Product/Service/Product.php b/src/Services/Catalog/Product/Service/Product.php new file mode 100644 index 00000000..730fd7c9 --- /dev/null +++ b/src/Services/Catalog/Product/Service/Product.php @@ -0,0 +1,143 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Catalog\Product\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\DeletedItemResult; +use Bitrix24\SDK\Core\Result\FieldsResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Catalog\Common\ProductType; +use Bitrix24\SDK\Services\Catalog\Product\Result\ProductResult; +use Bitrix24\SDK\Services\Catalog\Product\Result\ProductsResult; + +use Psr\Log\LoggerInterface; + +#[ApiServiceMetadata(new Scope(['catalog']))] +class Product extends AbstractService +{ + public function __construct( + public Batch $batch, + CoreInterface $core, + LoggerInterface $logger + ) + { + parent::__construct($core, $logger); + } + + /** + * The method gets field value of commercial catalog product by ID. + * + * @see https://training.bitrix24.com/rest_help/catalog/product/catalog_product_get.php + * @throws TransportException + * @throws BaseException + */ + #[ApiEndpointMetadata( + 'catalog.product.get', + 'https://training.bitrix24.com/rest_help/catalog/product/catalog_product_get.php', + 'The method gets field value of commercial catalog product by ID.' + )] + public function get(int $productId): ProductResult + { + return new ProductResult($this->core->call('catalog.product.get', ['id' => $productId])); + } + + /** + * The method adds a commercial catalog product. + * + * @see https://training.bitrix24.com/rest_help/catalog/product/catalog_product_add.php + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'catalog.product.add', + 'https://training.bitrix24.com/rest_help/catalog/product/catalog_product_add.php', + 'The method adds a commercial catalog product.' + )] + public function add(array $productFields): ProductResult + { + return new ProductResult($this->core->call('catalog.product.add', [ + 'fields' => $productFields + ] + )); + } + + /** + * The method deletes commercial catalog product. + * + * @see https://training.bitrix24.com/rest_help/catalog/product/catalog_product_delete.php + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'catalog.product.delete', + 'https://training.bitrix24.com/rest_help/catalog/product/catalog_product_delete.php', + 'The method deletes commercial catalog product by ID' + )] + public function delete(int $productId): DeletedItemResult + { + return new DeletedItemResult($this->core->call('catalog.product.delete', ['id' => $productId])); + } + + /** + * The method gets list of commercial catalog products by filter. + * + * @see https://training.bitrix24.com/rest_help/catalog/product/catalog_product_list.php + * @throws TransportException + * @throws BaseException + */ + #[ApiEndpointMetadata( + 'catalog.product.list', + 'https://training.bitrix24.com/rest_help/catalog/product/catalog_product_list.php', + 'The method gets list of commercial catalog products by filter.' + )] + public function list(array $select, array $filter, array $order, int $start): ProductsResult + { + return new ProductsResult($this->core->call('catalog.product.list', [ + 'select' => $select, + 'filter' => $filter, + 'order' => $order, + 'start' => $start + ])); + } + + /** + * The method returns commercial catalog product fields by filter. + * @see https://training.bitrix24.com/rest_help/catalog/product/catalog_product_getfieldsbyfilter.php + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'catalog.product.getFieldsByFilter', + 'https://training.bitrix24.com/rest_help/catalog/product/catalog_product_getfieldsbyfilter.php', + 'The method returns commercial catalog product fields by filter.' + )] + public function fieldsByFilter(int $iblockId, ProductType $productType, ?array $additionalFilter = null): FieldsResult + { + $filter = [ + 'iblockId' => $iblockId, + 'productType' => $productType->value + ]; + if ($additionalFilter !== null) { + $filter = array_merge($filter, $additionalFilter); + } + + return new FieldsResult($this->core->call('catalog.product.getFieldsByFilter', ['filter' => $filter])); + } +} \ No newline at end of file diff --git a/src/Services/IM/IMServiceBuilder.php b/src/Services/IM/IMServiceBuilder.php new file mode 100644 index 00000000..641eacd4 --- /dev/null +++ b/src/Services/IM/IMServiceBuilder.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\IM; + +use Bitrix24\SDK\Services\AbstractServiceBuilder; +use Bitrix24\SDK\Services\IM\Notify\Service\Notify; + +class IMServiceBuilder extends AbstractServiceBuilder +{ + public function notify(): Notify + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Notify($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } +} \ No newline at end of file diff --git a/src/Services/IM/Notify/Service/Notify.php b/src/Services/IM/Notify/Service/Notify.php new file mode 100644 index 00000000..27deffa7 --- /dev/null +++ b/src/Services/IM/Notify/Service/Notify.php @@ -0,0 +1,206 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\IM\Notify\Service; + + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\AddedItemResult; +use Bitrix24\SDK\Core\Result\DeletedItemResult; +use Bitrix24\SDK\Core\Result\UpdatedItemResult; +use Bitrix24\SDK\Services\AbstractService; + +#[ApiServiceMetadata(new Scope(['im']))] +class Notify extends AbstractService +{ + /** + * @param positive-int $userId + * @param non-empty-string $message + * @param non-empty-string|null $forEmailChannelMessage + * @param non-empty-string|null $notificationTag + * @param non-empty-string|null $subTag + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'im.notify.system.add', + 'https://training.bitrix24.com/support/training/course/index.php?COURSE_ID=115&LESSON_ID=23904&LESSON_PATH=9691.9805.11585.23904', + 'Sending system notification' + )] + public function fromSystem( + int $userId, + string $message, + ?string $forEmailChannelMessage = null, + ?string $notificationTag = null, + ?string $subTag = null, + ?array $attachment = null + ): AddedItemResult + { + return new AddedItemResult($this->core->call( + 'im.notify.system.add', + [ + 'USER_ID' => $userId, + 'MESSAGE' => $message, + 'MESSAGE_OUT' => $forEmailChannelMessage, + 'TAG' => $notificationTag, + 'SUB_TAG' => $subTag, + 'ATTACH' => $attachment, + ] + )); + } + + #[ApiEndpointMetadata( + 'im.notify.personal.add', + 'https://training.bitrix24.com/support/training/course/index.php?COURSE_ID=115&LESSON_ID=23904&LESSON_PATH=9691.9805.11585.23904', + 'Sending personal notification' + )] + public function fromPersonal( + int $userId, + string $message, + ?string $forEmailChannelMessage = null, + ?string $notificationTag = null, + ?string $subTag = null, + ?array $attachment = null + ): AddedItemResult + { + return new AddedItemResult($this->core->call( + 'im.notify.personal.add', + [ + 'USER_ID' => $userId, + 'MESSAGE' => $message, + 'MESSAGE_OUT' => $forEmailChannelMessage, + 'TAG' => $notificationTag, + 'SUB_TAG' => $subTag, + 'ATTACH' => $attachment, + ] + )); + } + + #[ApiEndpointMetadata( + 'im.notify.delete', + 'https://training.bitrix24.com/support/training/course/index.php?COURSE_ID=115&LESSON_ID=23906&LESSON_PATH=9691.9805.11585.23906', + 'Deleting notification' + )] + public function delete( + int $notificationId, + ?string $notificationTag = null, + ?string $subTag = null, + ): DeletedItemResult + { + return new DeletedItemResult($this->core->call( + 'im.notify.delete', + [ + 'ID' => $notificationId, + 'TAG' => $notificationTag, + 'SUB_TAG' => $subTag + ] + )); + } + + #[ApiEndpointMetadata( + 'im.notify.read', + 'https://training.bitrix24.com/support/training/course/index.php?COURSE_ID=115&LESSON_ID=11587&LESSON_PATH=9691.9805.11585.11587', + 'The method cancels notification for read messages.' + )] + public function markAsRead( + int $notificationId, + bool $isOnlyCurrent = true, + ): UpdatedItemResult + { + return new UpdatedItemResult($this->core->call( + 'im.notify.read', + [ + 'ID' => $notificationId, + 'ONLY_CURRENT' => $isOnlyCurrent ? 'Y' : 'N', + ] + )); + } + + #[ApiEndpointMetadata( + 'im.notify.read', + 'https://training.bitrix24.com/support/training/course/index.php?COURSE_ID=115&LESSON_ID=23908&LESSON_PATH=9691.9805.11585.23908', + '"Read" the list of notifications, excluding CONFIRM notification type' + )] + public function markMessagesAsRead( + array $notificationIds + ): UpdatedItemResult + { + return new UpdatedItemResult($this->core->call( + 'im.notify.read', + [ + 'IDS' => $notificationIds, + 'ACTION' => 'Y', + ] + )); + } + + #[ApiEndpointMetadata( + 'im.notify.read', + 'https://training.bitrix24.com/support/training/course/index.php?COURSE_ID=115&LESSON_ID=23908&LESSON_PATH=9691.9805.11585.23908', + '"Unread" the list of notifications, excluding CONFIRM notification type' + )] + public function markMessagesAsUnread( + array $notificationIds + ): UpdatedItemResult + { + return new UpdatedItemResult($this->core->call( + 'im.notify.read', + [ + 'IDS' => $notificationIds, + 'ACTION' => 'N', + ] + )); + } + + #[ApiEndpointMetadata( + 'im.notify.confirm', + 'https://training.bitrix24.com/support/training/course/index.php?COURSE_ID=115&LESSON_ID=23912&LESSON_PATH=9691.9805.11585.23912', + 'Interaction with notification buttons' + )] + public function confirm( + int $notificationId, + bool $isAccept + ): UpdatedItemResult + { + return new UpdatedItemResult($this->core->call( + 'im.notify.confirm', + [ + 'ID' => $notificationId, + 'NOTIFY_VALUE' => $isAccept ? 'Y' : 'N', + ] + )); + } + + #[ApiEndpointMetadata( + 'im.notify.answer', + 'https://training.bitrix24.com/support/training/course/index.php?COURSE_ID=115&LESSON_ID=23910&LESSON_PATH=9691.9805.11585.23910', + 'Response to notification, supporting quick reply' + )] + public function answer( + int $notificationId, + string $answerText + ): UpdatedItemResult + { + return new UpdatedItemResult($this->core->call( + 'im.notify.answer', + [ + 'ID' => $notificationId, + 'ANSWER_TEXT' => $answerText, + ] + )); + } +} \ No newline at end of file diff --git a/src/Services/IMOpenLines/IMOpenLinesServiceBuilder.php b/src/Services/IMOpenLines/IMOpenLinesServiceBuilder.php new file mode 100644 index 00000000..8218dde8 --- /dev/null +++ b/src/Services/IMOpenLines/IMOpenLinesServiceBuilder.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\IMOpenLines; + +use Bitrix24\SDK\Services\AbstractServiceBuilder; +use Bitrix24\SDK\Services\IMOpenLines\Service\Network; + +class IMOpenLinesServiceBuilder extends AbstractServiceBuilder +{ + public function Network(): Network + { + if (!isset($this->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..c29eb4da --- /dev/null +++ b/src/Services/IMOpenLines/Result/AddedMessageItemResult.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\IMOpenLines\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + + +class AddedMessageItemResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function isSuccess(): bool + { + return (bool)$this->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..a0a13a5e --- /dev/null +++ b/src/Services/IMOpenLines/Result/JoinOpenLineResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\IMOpenLines\Result; + +use Bitrix24\SDK\Core\Contracts\AddedItemIdResultInterface; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class JoinOpenLineResult extends AbstractResult implements AddedItemIdResultInterface +{ + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function getId(): int + { + return (int)$this->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..8d2c5720 --- /dev/null +++ b/src/Services/IMOpenLines/Service/Network.php @@ -0,0 +1,81 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\IMOpenLines\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\IMOpenLines\Result\AddedMessageItemResult; +use Bitrix24\SDK\Services\IMOpenLines\Result\JoinOpenLineResult; + +#[ApiServiceMetadata(new Scope(['imopenlines']))] +class Network extends AbstractService +{ + /** + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/support/training/course/?COURSE_ID=115&LESSON_ID=25016 + */ + #[ApiEndpointMetadata( + 'imopenlines.network.join', + 'https://training.bitrix24.com/support/training/course/?COURSE_ID=115&LESSON_ID=25016', + 'Connecting an open channel by code' + )] + public function join(string $openLineCode): JoinOpenLineResult + { + return new JoinOpenLineResult( + $this->core->call( + 'imopenlines.network.join', + [ + 'CODE' => $openLineCode, + ] + ) + ); + } + + /** + * @link https://training.bitrix24.com/support/training/course/?COURSE_ID=115&LESSON_ID=25018&LESSON_PATH=9691.9833.20331.25014.25018 + */ + #[ApiEndpointMetadata( + 'imopenlines.network.message.add', + 'https://training.bitrix24.com/support/training/course/?COURSE_ID=115&LESSON_ID=25018&LESSON_PATH=9691.9833.20331.25014.25018', + 'Sending Open Channel message to selected user' + )] + 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/Common/EventHandlerMetadata.php b/src/Services/Main/Common/EventHandlerMetadata.php new file mode 100644 index 00000000..3b6f6c7e --- /dev/null +++ b/src/Services/Main/Common/EventHandlerMetadata.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Main\Common; + +use Bitrix24\SDK\Services\Main\Result\EventHandlerItemResult; + +readonly class EventHandlerMetadata +{ + public function __construct( + public string $code, + public string $handlerUrl, + public int $userId, + public ?array $options = null + ) + { + } + + public function isInstalled(EventHandlerItemResult $eventHandlerItemResult): bool + { + return strtoupper($eventHandlerItemResult->event) === strtoupper($this->code) && + $eventHandlerItemResult->handler === $this->handlerUrl; + } +} \ No newline at end of file diff --git a/src/Services/Main/MainServiceBuilder.php b/src/Services/Main/MainServiceBuilder.php new file mode 100644 index 00000000..b986a3a4 --- /dev/null +++ b/src/Services/Main/MainServiceBuilder.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Main; + +use Bitrix24\SDK\Services\AbstractServiceBuilder; +use Bitrix24\SDK\Services\Main\Service\EventManager; +use Bitrix24\SDK\Services\Main\Service\Main; +use Bitrix24\SDK\Services\Main\Service\Event; + +/** + * Class MainServiceBuilder + * + * @package Bitrix24\SDK\Services\Main + */ +class MainServiceBuilder extends AbstractServiceBuilder +{ + public function main(): Main + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Main($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + public function event(): Event + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Event($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + public function eventManager(): EventManager + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new EventManager( + new Event($this->core, $this->log), + $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..9d621709 --- /dev/null +++ b/src/Services/Main/Result/ApplicationInfoItemResult.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Main\Result; + +use Bitrix24\SDK\Application\ApplicationStatus; +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * Class ApplicationInfoResult + * + * @property-read int $ID + * @property-read string $CODE + * @property-read array $SCOPE + * @property-read int $VERSION + * @property-read string $STATUS + * @property-read boolean $INSTALLED + * @property-read string $PAYMENT_EXPIRED + * @property-read int $DAYS + * @property-read string $LICENSE + */ +class ApplicationInfoItemResult extends AbstractItem +{ + /** + * @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/ApplicationInfoResult.php b/src/Services/Main/Result/ApplicationInfoResult.php new file mode 100644 index 00000000..fcd58be8 --- /dev/null +++ b/src/Services/Main/Result/ApplicationInfoResult.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Main\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class ApplicationInfoResult extends AbstractResult +{ + public function applicationInfo(): ApplicationInfoItemResult + { + return new ApplicationInfoItemResult($this->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..85a24630 --- /dev/null +++ b/src/Services/Main/Result/EventHandlerBindResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Main\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class EventHandlerBindResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function isBinded(): bool + { + return (bool)$this->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..98a994a1 --- /dev/null +++ b/src/Services/Main/Result/EventHandlerItemResult.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Main\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read string $event + * @property-read string $handler + * @property-read string $auth_type + * @property-read int $offline + */ +class EventHandlerItemResult extends AbstractItem +{ +} \ No newline at end of file diff --git a/src/Services/Main/Result/EventHandlerUnbindResult.php b/src/Services/Main/Result/EventHandlerUnbindResult.php new file mode 100644 index 00000000..7c358b10 --- /dev/null +++ b/src/Services/Main/Result/EventHandlerUnbindResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Main\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class EventHandlerUnbindResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function getUnbindedHandlersCount(): int + { + return (int)$this->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..77a466ca --- /dev/null +++ b/src/Services/Main/Result/EventHandlersResult.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Main\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class EventHandlersResult extends AbstractResult +{ + /** + * @return EventHandlerItemResult[] + * @throws BaseException + */ + public function getEventHandlers(): array + { + $res = []; + foreach ($this->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..d7733fc4 --- /dev/null +++ b/src/Services/Main/Result/EventListResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Main\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class EventListResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function getEvents(): array + { + return $this->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..ef68bc11 --- /dev/null +++ b/src/Services/Main/Result/IsUserAdminResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Main\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class IsUserAdminResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function isAdmin(): bool + { + return (bool)$this->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..4ca9c08a --- /dev/null +++ b/src/Services/Main/Result/MethodAffordabilityResult.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Main\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class MethodAffordabilityResult extends AbstractResult +{ + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function isExisting(): bool + { + return $this->getCoreResponse()->getResponseData()->getResult()['isExisting']; + } + + /** + * @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..819c3dc6 --- /dev/null +++ b/src/Services/Main/Result/ServerTimeResult.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Main\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; +use Carbon\CarbonImmutable; +use Exception; + +class ServerTimeResult extends AbstractResult +{ + /** + * @throws BaseException + * @throws Exception + */ + public function time(): CarbonImmutable + { + return new CarbonImmutable($this->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..250db094 --- /dev/null +++ b/src/Services/Main/Result/UserProfileItemResult.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Main\Result; + +use Bitrix24\SDK\Application\ApplicationStatus; +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * Class ApplicationInfoResult + * + * @property-read boolean $ADMIN + * @property-read int $ID + * @property-read string $LAST_NAME + * @property-read string $NAME + * @property-read string $PERSONAL_GENDER + * @property-read string $PERSONAL_PHOTO + * @property-read string $TIME_ZONE + * @property-read int $TIME_ZONE_OFFSET + * @property-read string $STATUS + */ +class UserProfileItemResult extends AbstractItem +{ + public function __get($offset) + { + switch ($offset) { + case 'ID': + if ($this->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..3826967f --- /dev/null +++ b/src/Services/Main/Result/UserProfileResult.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Main\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class UserProfileResult extends AbstractResult +{ + public function getUserProfile(): UserProfileItemResult + { + return new UserProfileItemResult($this->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..cc733ddb --- /dev/null +++ b/src/Services/Main/Service/Event.php @@ -0,0 +1,146 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Main\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException; +use Bitrix24\SDK\Core\Response\Response; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Main\Result\EventHandlerBindResult; +use Bitrix24\SDK\Services\Main\Result\EventHandlersResult; +use Bitrix24\SDK\Services\Main\Result\EventHandlerUnbindResult; +use Bitrix24\SDK\Services\Main\Result\EventListResult; + +#[ApiServiceMetadata(new Scope([]))] +class Event extends AbstractService +{ + /** + * Displays events from the general list of events. + * + * + * @throws BaseException + * @throws TransportException + * @throws UnknownScopeCodeException + * @link https://training.bitrix24.com/rest_help/general/events_method/events.php + */ + #[ApiEndpointMetadata( + 'events', + 'https://training.bitrix24.com/rest_help/general/events_method/events.php', + 'Displays events from the general list of events.' + )] + public function list(?string $scopeCode = null): EventListResult + { + return new EventListResult( + $this->core->call( + 'events', + $scopeCode !== null ? ['scope' => (new Scope([$scopeCode]))->getScopeCodes()[0]] : [] + ) + ); + } + + /** + * Installs a new event handler. + * + * + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/general/events_method/event_bind.php + */ + #[ApiEndpointMetadata( + 'event.bind', + 'https://training.bitrix24.com/rest_help/general/events_method/event_bind.php', + 'Installs a new event handler.' + )] + 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. + * + * + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/general/events_method/event_unbind.php + */ + #[ApiEndpointMetadata( + 'event.unbind', + 'https://training.bitrix24.com/rest_help/general/events_method/event_unbind.php', + 'Uninstalls a previously installed event handler.' + )] + 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)); + } + + /** + * + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/rest_sum/test_handler.php + */ + #[ApiEndpointMetadata( + 'event.test', + 'https://training.bitrix24.com/rest_help/rest_sum/test_handler.php', + 'Test events' + )] + public function test(array $payload = []): Response + { + return $this->core->call('event.test', $payload); + } + + /** + * Obtaining a list of registered event handlers. + * + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/general/events_method/event_get.php + */ + #[ApiEndpointMetadata( + 'event.get', + 'https://training.bitrix24.com/rest_help/general/events_method/event_get.php', + 'Obtaining a list of registered event handlers.' + )] + 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/EventManager.php b/src/Services/Main/Service/EventManager.php new file mode 100644 index 00000000..084e91ba --- /dev/null +++ b/src/Services/Main/Service/EventManager.php @@ -0,0 +1,119 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Main\Service; + +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Services\Main\Common\EventHandlerMetadata; +use Bitrix24\SDK\Services\Main\Result\EventHandlersResult; +use Psr\Log\LoggerInterface; + +readonly class EventManager +{ + public function __construct( + protected Event $eventService, + protected LoggerInterface $logger + ) + { + } + + /** + * @param EventHandlerMetadata[] $eventHandlerMetadata + * @throws InvalidArgumentException + */ + public function bindEventHandlers(array $eventHandlerMetadata): void + { + // check input arguments + foreach ($eventHandlerMetadata as $eventHandler) { + if (!$eventHandler instanceof EventHandlerMetadata) { + throw new InvalidArgumentException( + sprintf('in eventHandlerMetadata we need only EventHandlerMetadata objects, we got an «%s»', gettype($eventHandler))); + } + + $this->logger->debug('bindEventHandlers.handlerItem', [ + 'code' => $eventHandler->code, + 'url' => $eventHandler->handlerUrl, + 'userId' => $eventHandler->userId, + 'options' => $eventHandler->options + ]); + } + + // is handler already installed? + $toInstall = []; + $alreadyInstalledHandlers = $this->eventService->get()->getEventHandlers(); + foreach ($eventHandlerMetadata as $eventHandler) { + $isInstalled = false; + foreach ($alreadyInstalledHandlers as $alreadyInstalledHandler) { + $this->logger->debug('bindEventHandlers.isHandlerInstalled', [ + 'handlerToInstallCode' => $eventHandler->code, + 'handlerToInstallUrl' => $eventHandler->handlerUrl, + 'isInstalled' => $eventHandler->isInstalled($alreadyInstalledHandler) + ]); + if ($eventHandler->isInstalled($alreadyInstalledHandler)) { + $this->logger->debug('bindEventHandlers.handlerAlreadyInstalled', [ + 'code' => $eventHandler->code, + 'handlerUrl' => $eventHandler->handlerUrl + ]); + + $isInstalled = true; + break; + } + } + + if (!$isInstalled) { + $toInstall[] = $eventHandler; + $this->logger->debug('bindEventHandlers.handlerAddedToInstallPlan', [ + 'code' => $eventHandler->code, + 'handlerUrl' => $eventHandler->handlerUrl + ]); + } + } + + // install event handlers + $this->logger->debug('bindEventHandlers.handlersToInstall', [ + 'count' => count($toInstall) + ]); + // todo replace to batch call + foreach ($toInstall as $eventHandler) { + $this->eventService->bind( + $eventHandler->code, + $eventHandler->handlerUrl, + $eventHandler->userId, + $eventHandler->options + ); + } + } + + public function unbindAllEventHandlers(): EventHandlersResult + { + $eventHandlersResult = $this->eventService->get(); + if ($eventHandlersResult->getEventHandlers() === []) { + return $eventHandlersResult; + } + + $handlersToUnbind = $eventHandlersResult->getEventHandlers(); + // todo replace to batch call + foreach ($handlersToUnbind as $handlerToUnbind) { + $this->logger->debug('unbindAllEventHandlers.handler', [ + 'code' => $handlerToUnbind->event, + 'handler' => $handlerToUnbind->handler, + ]); + $this->eventService->unbind( + $handlerToUnbind->event, + $handlerToUnbind->handler + ); + } + + return $eventHandlersResult; + } +} \ No newline at end of file diff --git a/src/Services/Main/Service/Main.php b/src/Services/Main/Service/Main.php new file mode 100644 index 00000000..ad06d9a9 --- /dev/null +++ b/src/Services/Main/Service/Main.php @@ -0,0 +1,250 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Main\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +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; + +#[ApiServiceMetadata(new Scope([]))] +class Main extends AbstractService +{ + /** + * 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 + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'server.time', + 'https://training.bitrix24.com/rest_help/general/server_time.php', + 'Method returns current server time in the format YYYY-MM-DDThh:mm:ss±hh:mm.' + )] + 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 + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'profile', + 'https://training.bitrix24.com/rest_help/general/profile.php', + 'Allows to return basic Information about the current user without any scopes, in contrast to user.current.' + )] + public function getCurrentUserProfile(): UserProfileResult + { + return new UserProfileResult($this->core->call('profile')); + } + + /** + * Returns access permission names. + * + * + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/general/access_name.php + */ + #[ApiEndpointMetadata( + 'access.name', + 'https://training.bitrix24.com/rest_help/general/access_name.php', + 'Returns access permission names.' + )] + public function getAccessName(array $accessList): Response + { + return $this->core->call('access.name', [ + 'ACCESS' => $accessList, + ]); + } + + /** + * Checks if the current user has at least one permission of those specified by the ACCESS parameter. + * + * + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/general/user_access.php + */ + #[ApiEndpointMetadata( + 'user.access', + 'https://training.bitrix24.com/rest_help/general/user_access.php', + 'Checks if the current user has at least one permission of those specified by the ACCESS parameter.' + )] + public function checkUserAccess(array $accessToCheck): Response + { + return $this->core->call('user.access', [ + 'ACCESS' => $accessToCheck, + ]); + } + + /** + * Method returns 2 parameters - isExisting and isAvailable + * + * + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/general/method_get.php + */ + #[ApiEndpointMetadata( + 'method.get', + 'https://training.bitrix24.com/rest_help/general/method_get.php', + 'Method returns 2 parameters - isExisting and isAvailable' + )] + 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. + * + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/general/scope.php + */ + #[ApiEndpointMetadata( + 'scope', + 'https://training.bitrix24.com/rest_help/general/scope.php', + 'Method returns 2 parameters - isExisting and isAvailable' + )] + public function getCurrentScope(): Response + { + return $this->core->call('scope'); + } + + /** + * Method will return a list of all possible permissions. + * + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/general/scope.php + */ + #[ApiEndpointMetadata( + 'scope', + 'https://training.bitrix24.com/rest_help/general/scope.php', + 'Method will return a list of all possible permissions.' + )] + public function getAvailableScope(): Response + { + return $this->core->call('scope', ['full' => true]); + } + + /** + * Returns the methods available to the current application + * + * @throws BaseException + * @throws TransportException + * @deprecated use method.get + * @link https://training.bitrix24.com/rest_help/general/methods.php + */ + #[ApiEndpointMetadata( + 'methods', + 'https://training.bitrix24.com/rest_help/general/methods.php', + 'Returns the methods available to the current application' + )] + public function getAvailableMethods(): Response + { + return $this->core->call('methods', []); + } + + /** + * Returns the methods available + * + * @throws BaseException + * @throws TransportException + * @deprecated use method.get + * @link https://training.bitrix24.com/rest_help/general/methods.php + */ + #[ApiEndpointMetadata( + 'methods', + 'https://training.bitrix24.com/rest_help/general/methods.php', + 'Returns the methods available to the current application' + )] + public function getAllMethods(): Response + { + return $this->core->call('methods', ['full' => true]); + } + + /** + * Returns the methods available to the current application + * + * + * @throws BaseException + * @throws TransportException + * @deprecated use method.get + * @link https://training.bitrix24.com/rest_help/general/methods.php + */ + #[ApiEndpointMetadata( + 'methods', + 'https://training.bitrix24.com/rest_help/general/methods.php', + 'Returns the methods available to the current application' + )] + public function getMethodsByScope(string $scope): Response + { + return $this->core->call('methods', ['scope' => $scope]); + } + + /** + * Displays application information. The method supports secure calling convention. + * + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/general/app_info.php + */ + #[ApiEndpointMetadata( + 'app.info', + 'https://training.bitrix24.com/rest_help/general/app_info.php', + 'Displays application information. The method supports secure calling convention.' + )] + public function getApplicationInfo(): ApplicationInfoResult + { + return new ApplicationInfoResult($this->core->call('app.info')); + } + + /** + * Checks if a current user has permissions to manage application parameters. + * + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/general/user_admin.php + */ + #[ApiEndpointMetadata( + 'user.admin', + 'https://training.bitrix24.com/rest_help/general/user_admin.php', + 'Checks if a current user has permissions to manage application parameters.' + )] + public function isCurrentUserHasAdminRights(): IsUserAdminResult + { + 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..cfefa8f9 --- /dev/null +++ b/src/Services/Placement/PlacementServiceBuilder.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Placement; + +use Bitrix24\SDK\Services\AbstractServiceBuilder; +use Bitrix24\SDK\Services\Placement\Service\Placement; +use Bitrix24\SDK\Services\Placement\Service\UserFieldType; + +class PlacementServiceBuilder extends AbstractServiceBuilder +{ + public function placement(): Placement + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Placement($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + 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..67d01d05 --- /dev/null +++ b/src/Services/Placement/Result/DeleteUserTypeResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Placement\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class DeleteUserTypeResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function isSuccess(): bool + { + return (bool)$this->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..4cf00d6a --- /dev/null +++ b/src/Services/Placement/Result/PlacementBindResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Placement\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class PlacementBindResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function isSuccess(): bool + { + return (bool)$this->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..9490c7c7 --- /dev/null +++ b/src/Services/Placement/Result/PlacementLocationCodesResult.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Placement\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class PlacementLocationCodesResult extends AbstractResult +{ + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function getLocationCodes(): array + { + return $this->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..5f0415c5 --- /dev/null +++ b/src/Services/Placement/Result/PlacementLocationItemResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Placement\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read string $placement + * @property-read string $handler + * @property-read string $title + * @property-read string $description + * @property-read array $options + * @property-read array $langAll + */ +class PlacementLocationItemResult extends AbstractItem +{ +} \ No newline at end of file diff --git a/src/Services/Placement/Result/PlacementUnbindResult.php b/src/Services/Placement/Result/PlacementUnbindResult.php new file mode 100644 index 00000000..41e14e02 --- /dev/null +++ b/src/Services/Placement/Result/PlacementUnbindResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Placement\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class PlacementUnbindResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function getDeletedPlacementHandlersCount(): int + { + return (int)$this->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..f817566e --- /dev/null +++ b/src/Services/Placement/Result/PlacementsLocationInformationResult.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Placement\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class PlacementsLocationInformationResult extends AbstractResult +{ + /** + * @return PlacementLocationItemResult[] + * @throws BaseException + */ + public function getPlacementsLocationInformation(): array + { + $res = []; + foreach ($this->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..a72e7e60 --- /dev/null +++ b/src/Services/Placement/Result/RegisterUserTypeResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Placement\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class RegisterUserTypeResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function isSuccess(): bool + { + return (bool)$this->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..a0e80a6f --- /dev/null +++ b/src/Services/Placement/Result/UserFieldTypeItemResult.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Placement\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read string $DESCRIPTION + * @property-read string $HANDLER + * @property-read string $TITLE + * @property-read string $USER_TYPE_ID + */ +class UserFieldTypeItemResult extends AbstractItem +{ +} \ No newline at end of file diff --git a/src/Services/Placement/Result/UserFieldTypesResult.php b/src/Services/Placement/Result/UserFieldTypesResult.php new file mode 100644 index 00000000..75e677cc --- /dev/null +++ b/src/Services/Placement/Result/UserFieldTypesResult.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Placement\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class UserFieldTypesResult extends AbstractResult +{ + /** + * @return UserFieldTypeItemResult[] + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function getUserFieldTypes(): array + { + $res = []; + foreach ($this->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..ec302ecf --- /dev/null +++ b/src/Services/Placement/Service/Placement.php @@ -0,0 +1,118 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Placement\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Placement\Result\PlacementBindResult; +use Bitrix24\SDK\Services\Placement\Result\PlacementLocationCodesResult; +use Bitrix24\SDK\Services\Placement\Result\PlacementsLocationInformationResult; +use Bitrix24\SDK\Services\Placement\Result\PlacementUnbindResult; +#[ApiServiceMetadata(new Scope(['placement']))] +class Placement extends AbstractService +{ + /** + * Installs the embedding location handler + * + * + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/application_embedding/metods/placement_bind.php + */ + #[ApiEndpointMetadata( + 'placement.bind', + 'https://training.bitrix24.com/rest_help/application_embedding/metods/placement_bind.php', + 'Installs the embedding location handler' + )] + public function bind(string $placementCode, string $handlerUrl, array $lang): PlacementBindResult + { + return new PlacementBindResult( + $this->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. + * + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/application_embedding/metods/placement_unbind.php + */ + #[ApiEndpointMetadata( + 'placement.unbind', + 'https://training.bitrix24.com/rest_help/application_embedding/metods/placement_unbind.php', + 'Deletes the registered embedding location handler. Shall be executed with the available account administrative privileges.' + )] + 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. + * + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/application_embedding/metods/placement_list.php + */ + #[ApiEndpointMetadata( + 'placement.list', + 'https://training.bitrix24.com/rest_help/application_embedding/metods/placement_list.php', + 'This method is used to retrieve the list of embedding locations, available to the application.' + )] + 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. + * + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/application_embedding/metods/placement_get.php + */ + #[ApiEndpointMetadata( + 'placement.get', + 'https://training.bitrix24.com/rest_help/application_embedding/metods/placement_get.php', + 'This method is used to retrieve the list of registered handlers for embedding locations.' + )] + 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..9217e71d --- /dev/null +++ b/src/Services/Placement/Service/PlacementLocationCode.php @@ -0,0 +1,251 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Placement\Service; + +/** + * @link https://training.bitrix24.com/rest_help/application_embedding/index.php + */ +class PlacementLocationCode +{ + // CRM scope + public const CRM_LEAD_LIST_MENU = 'CRM_LEAD_LIST_MENU'; + + // List menu for Leads + public const CRM_LEAD_DETAIL_TAB = 'CRM_LEAD_DETAIL_TAB'; + + // Upper menu item in the Lead details tab + public const CRM_LEAD_DETAIL_ACTIVITY = 'CRM_LEAD_DETAIL_ACTIVITY'; + + // Lead activity menu item + public const CRM_DEAL_LIST_MENU = 'CRM_DEAL_LIST_MENU'; + + //Deals list menu + public const CRM_DEAL_DETAIL_TAB = 'CRM_DEAL_DETAIL_TAB'; + + // Upper menu item in the Deals details + public const CRM_DEAL_DETAIL_ACTIVITY = 'CRM_DEAL_DETAIL_ACTIVITY'; + + // Deal activity menu item + public const CRM_CONTACT_LIST_MENU = 'CRM_CONTACT_LIST_MENU'; + + // Contact list menu + public const CRM_CONTACT_DETAIL_TAB = 'CRM_CONTACT_DETAIL_TAB'; + + // Upper menu item in the Contact details + public const CRM_CONTACT_DETAIL_ACTIVITY = 'CRM_CONTACT_DETAIL_ACTIVITY'; + + // Contact activity menu item + public const CRM_COMPANY_LIST_MENU = 'CRM_COMPANY_LIST_MENU'; + + // Company list menu + public const CRM_COMPANY_DETAIL_TAB = 'CRM_COMPANY_DETAIL_TAB'; + + // Upper menu item in the Company details + public const CRM_COMPANY_DETAIL_ACTIVITY = 'CRM_COMPANY_DETAIL_ACTIVITY'; + + // Company activity menu item + public const CRM_INVOICE_LIST_MENU = 'CRM_INVOICE_LIST_MENU'; + + // Invoices list menu + public const CRM_QUOTE_LIST_MENU = 'CRM_QUOTE_LIST_MENU'; + + // Quotes list context menu + public const CRM_ACTIVITY_LIST_MENU = 'CRM_ACTIVITY_LIST_MENU'; + + // Activities list context menu + public const CRM_ANALYTICS_MENU = 'CRM_ANALYTICS_MENU'; + + // CRM Analytics menu + public const CRM_FUNNELS_TOOLBAR = 'CRM_FUNNELS_TOOLBAR'; + + public const CRM_ANALYTICS_TOOLBAR = 'CRM_ANALYTICS_TOOLBAR'; + + public const CRM_DEAL_LIST_TOOLBAR = 'CRM_DEAL_LIST_TOOLBAR'; + + // Option in Automation Rules dropdown menu + public const CRM_LEAD_LIST_TOOLBAR = 'CRM_LEAD_LIST_TOOLBAR'; + + // Option in Automation Rules dropdown menu + public const CRM_CONTACT_LIST_TOOLBAR = 'CRM_CONTACT_LIST_TOOLBAR'; + + // Option in Automation Rules dropdown menu + public const CRM_COMPANY_LIST_TOOLBAR = 'CRM_COMPANY_LIST_TOOLBAR'; + + // Option in Automation Rules dropdown menu + public const CRM_INVOICE_LIST_TOOLBAR = 'CRM_INVOICE_LIST_TOOLBAR'; + + // Option in Automation Rules dropdown menu + public const CRM_QUOTE_LIST_TOOLBAR = 'CRM_QUOTE_LIST_TOOLBAR'; + + // Option in Automation Rules dropdown menu + public const CRM_DEAL_DETAIL_TOOLBAR = 'CRM_DEAL_DETAIL_TOOLBAR'; + + // Button at the upper section of CRM details. + public const CRM_LEAD_DETAIL_TOOLBAR = 'CRM_LEAD_DETAIL_TOOLBAR'; + + // Button at the upper section of CRM details. + public const CRM_CONTACT_DETAIL_TOOLBAR = 'CRM_CONTACT_DETAIL_TOOLBAR'; + + // Button at the upper section of CRM details. + public const CRM_COMPANY_DETAIL_TOOLBAR = 'CRM_COMPANY_DETAIL_TOOLBAR'; + + // Button at the upper section of CRM details. + public const CRM_INVOICE_DETAIL_TOOLBAR = 'CRM_INVOICE_DETAIL_TOOLBAR'; + + // Button at the upper section of CRM details. + public const CRM_QUOTE_DETAIL_TOOLBAR = 'CRM_QUOTE_DETAIL_TOOLBAR'; + + // Button at the upper section of CRM details. + public const CRM_DEAL_ACTIVITY_TIMELINE_MENU = 'CRM_DEAL_ACTIVITY_TIMELINE_MENU'; + + // Button in the object context menu + public const CRM_LEAD_ACTIVITY_TIMELINE_MENU = 'CRM_LEAD_ACTIVITY_TIMELINE_MENU'; + + // Button in the object context menu + public const CRM_DEAL_DOCUMENTGENERATOR_BUTTON = 'CRM_DEAL_DOCUMENTGENERATOR_BUTTON'; + + // Button in documents. + public const CRM_LEAD_DOCUMENTGENERATOR_BUTTON = 'CRM_LEAD_DOCUMENTGENERATOR_BUTTON'; + + // Button in documents. + public const CRM_DEAL_ROBOT_DESIGNER_TOOLBAR = 'CRM_DEAL_ROBOT_DESIGNER_TOOLBAR'; + + // Option in cogwheel dropdown menu with automation rules + public const CRM_LEAD_ROBOT_DESIGNER_TOOLBAR = 'CRM_LEAD_ROBOT_DESIGNER_TOOLBAR'; // Option in cogwheel dropdown menu with automation rules + + public const TASK_USER_LIST_TOOLBAR = 'TASK_USER_LIST_TOOLBAR'; + + // Option in Automation Rules dropdown menu. You must pass user ID in placement_options. + public const TASK_GROUP_LIST_TOOLBAR = 'TASK_GROUP_LIST_TOOLBAR'; + + // Option in Automation Rules dropdown menu. You must pass workgroup ID in placement_options. + public const TASK_ROBOT_DESIGNER_TOOLBAR = 'TASK_ROBOT_DESIGNER_TOOLBAR'; + + // Option in cogwheel dropdown menu with automation rule. + public const SONET_GROUP_ROBOT_DESIGNER_TOOLBAR = 'SONET_GROUP_ROBOT_DESIGNER_TOOLBAR'; + + // Option in Automation Rules dropdown menu in workgroup. You must pass current workgroup ID in placement_options. + public const SONET_GROUP_TOOLBAR = 'SONET_GROUP_TOOLBAR'; + + // Option in Automation Rules dropdown menu inside workgroup. You must pass current workgroup ID in placement_options идентификатор текущей группы. + public const USER_PROFILE_MENU = 'USER_PROFILE_MENU'; + + // Option with dropdown selection in the upper Bitrix24 account main menu. You must pass current user ID in placement_options. + public const USER_PROFILE_TOOLBAR = 'USER_PROFILE_TOOLBAR'; + + // Option in dropdown menu inside user profile. You must pass current user ID in placement_options. + public const CRM_SMART_INVOICE_LIST_TOOLBAR = 'CRM_SMART_INVOICE_LIST_TOOLBAR'; + + public const CRM_SMART_INVOICE_DETAIL_TOOLBAR = 'CRM_SMART_INVOICE_DETAIL_TOOLBAR'; + + public const CRM_SMART_INVOICE_ACTIVITY_TIMELINE_MENU = 'CRM_SMART_INVOICE_ACTIVITY_TIMELINE_MENU'; + + public const CRM_SMART_INVOICE_FUNNELS_TOOLBAR = 'CRM_SMART_INVOICE_FUNNELS_TOOLBAR'; + + public const CRM_SMART_INVOICE_ROBOT_DESIGNER_TOOLBAR = 'CRM_SMART_INVOICE_ROBOT_DESIGNER_TOOLBAR'; + + public const CRM_SMART_INVOICE_DETAIL_TAB = 'CRM_SMART_INVOICE_DETAIL_TAB'; + + public const CRM_SMART_INVOICE_LIST_MENU = 'CRM_SMART_INVOICE_LIST_MENU'; + + public const CRM_SMART_INVOICE_DETAIL_ACTIVITY = 'CRM_SMART_INVOICE_DETAIL_ACTIVITY'; + + public const CRM_CONTACT_DOCUMENTGENERATOR_BUTTON = 'CRM_CONTACT_DOCUMENTGENERATOR_BUTTON'; + + public const CRM_COMPANY_DOCUMENTGENERATOR_BUTTON = 'CRM_COMPANY_DOCUMENTGENERATOR_BUTTON'; + + public const CRM_INVOICE_DOCUMENTGENERATOR_BUTTON = 'CRM_INVOICE_DOCUMENTGENERATOR_BUTTON'; + + public const CRM_QUOTE_DOCUMENTGENERATOR_BUTTON = 'CRM_QUOTE_DOCUMENTGENERATOR_BUTTON'; + + public const CRM_SMART_INVOICE_DOCUMENTGENERATOR_BUTTON = 'CRM_SMART_INVOICE_DOCUMENTGENERATOR_BUTTON'; + + public const CRM_REQUISITE_EDIT_FORM = 'CRM_REQUISITE_EDIT_FORM'; + + public const MAIN_1C_PAGE = '1C_PAGE'; + + public const CRM_DETAIL_SEARCH = 'CRM_DETAIL_SEARCH'; + + + // ExternalLine scope + public const CALL_CARD = 'CALL_CARD'; + + // Call ID screen + public const TELEPHONY_ANALYTICS_MENU = 'TELEPHONY_ANALYTICS_MENU'; + + // Landing Scope + public const LANDING_SETTINGS = 'LANDING_SETTINGS'; + + // Settings menu (for Landing Page / Site) + public const LANDING_BLOCK = 'LANDING_BLOCK'; // Edit option for any block. + + // Workgroups scope + public const SONET_GROUP_DETAIL_TAB = 'SONET_GROUP_DETAIL_TAB'; // Workgroup detail tab. + + // scope task + public const TASK_LIST_CONTEXT_MENU = 'TASK_LIST_CONTEXT_MENU'; + + // Task list context menu. + public const TASK_VIEW_TAB = 'TASK_VIEW_TAB'; + + // New tab when viewing task + public const TASK_VIEW_SIDEBAR = 'TASK_VIEW_SIDEBAR'; + + // New side bar when viewing task + public const TASK_VIEW_TOP_PANEL = 'TASK_VIEW_TOP_PANEL'; // Top panel when viewing task + + // Calendar scope + public const CALENDAR_GRIDVIEW = 'CALENDAR_GRIDVIEW'; // List of calendar grid views + + // Contact_Center scope + public const CONTACT_CENTER = 'CONTACT_CENTER'; // Square tile in the list of Contact Center. + + // Arbitrary location + // This embedding does not have an UI button that user can use to manually open the app. + // The app can send a link, leading to its embedding to any location (Instant Messenger, Feed and etc.). + // To use this embedding option, the link must have the format /marketplace/view/#APP_CODE#/, + // where #APP_CODE# - your app code. + // + // The embedding can receive any number of parameters in the "get" key params, + // for example: /marketplace/view/#APP_CODE#/?params[test]=y. + // The link can be embedded in any text field which supports BBCode or inside your other embedding locations as a standard link. + // The GET parameter params can be used to modify the displayed parameters in the embedding. + // You can use this option in any various scenarios by passing any number of parameters into GET key params, + // for example: ?params[test]=yy. + public const REST_APP_URI = 'REST_APP_URI'; + + // Each account/portal allows for each individual application to register only a single embedding using the method placement.bind. + // errorHandlerUrl - required field with error handler URL. + // When the embedding upload takes a long period of time (longer than 3-5 seconds), + // this URL receives a message with text and error code and the embedding itself is deleted. + public const PAGE_BACKGROUND_WORKER = 'PAGE_BACKGROUND_WORKER'; + + + public function getForCrmDynamicListMenu(int $entityId): string + { + return sprintf('CRM_DYNAMIC_%s_LIST_MENU', $entityId); + } + + + public function getForCrmDynamicDetailTab(int $entityId): string + { + return sprintf('CRM_DYNAMIC_%s_DETAIL_TAB', $entityId); + } + + + public function getForCrmDynamicDetailActivity(int $entityId): string + { + return sprintf('CRM_DYNAMIC_%s_DETAIL_ACTIVITY', $entityId); + } +} \ No newline at end of file diff --git a/src/Services/Placement/Service/UserFieldType.php b/src/Services/Placement/Service/UserFieldType.php new file mode 100644 index 00000000..75d706a4 --- /dev/null +++ b/src/Services/Placement/Service/UserFieldType.php @@ -0,0 +1,136 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Placement\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Placement\Result\DeleteUserTypeResult; +use Bitrix24\SDK\Services\Placement\Result\RegisterUserTypeResult; +use Bitrix24\SDK\Services\Placement\Result\UserFieldTypesResult; +#[ApiServiceMetadata(new Scope(['placement']))] +class UserFieldType extends AbstractService +{ + /** + * Registration of new type of user fields. 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. + * + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/application_embedding/user_field/userfieldtype_add.php + */ + #[ApiEndpointMetadata( + 'userfieldtype.add', + 'https://training.bitrix24.com/rest_help/application_embedding/user_field/userfieldtype_add.php', + 'Registration of new type of user fields. This method returns true or an error with description.' + )] + public function add(string $userTypeId, string $handlerUrl, string $title, string $description): RegisterUserTypeResult + { + return new RegisterUserTypeResult( + $this->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. + * + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/application_embedding/user_field/userfieldtype_list.php + */ + #[ApiEndpointMetadata( + 'userfieldtype.list', + 'https://training.bitrix24.com/rest_help/application_embedding/user_field/userfieldtype_list.php', + 'Retrieves list of user field types, registrered by the application. List method. Results in the list of field types with page-by-page navigation.' + )] + 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. + * + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/application_embedding/user_field/userfieldtype_update.php + */ + #[ApiEndpointMetadata( + 'userfieldtype.update', + 'https://training.bitrix24.com/rest_help/application_embedding/user_field/userfieldtype_update.php', + 'Modifies settings of user field types, registered by the application. This method returns true or an error with description.' + )] + 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 + * + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/application_embedding/user_field/userfieldtype_delete.php + */ + #[ApiEndpointMetadata( + 'userfieldtype.delete', + 'https://training.bitrix24.com/rest_help/application_embedding/user_field/userfieldtype_delete.php', + 'Deletes user field type, registered by the application. This method returns true or an error with description.' + )] + 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 new file mode 100644 index 00000000..8d646598 --- /dev/null +++ b/src/Services/ServiceBuilder.php @@ -0,0 +1,124 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services; + +use Bitrix24\SDK\Services\Catalog\CatalogServiceBuilder; +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\User\UserServiceBuilder; +use Bitrix24\SDK\Services\UserConsent\UserConsentServiceBuilder; +use Bitrix24\SDK\Services\Placement\PlacementServiceBuilder; +use Bitrix24\SDK\Services\Workflows\WorkflowsServiceBuilder; + +class ServiceBuilder extends AbstractServiceBuilder +{ + public function getCRMScope(): CRMServiceBuilder + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new CRMServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + public function getIMScope(): IMServiceBuilder + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new IMServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + 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 + */ + public function getMainScope(): MainServiceBuilder + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new MainServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + 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__]; + } + + public function getUserScope(): UserServiceBuilder + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new UserServiceBuilder($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__]; + } + + public function getCatalogScope(): CatalogServiceBuilder + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new CatalogServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + public function getBizProcScope(): WorkflowsServiceBuilder + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new WorkflowsServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + 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/ServiceBuilderFactory.php b/src/Services/ServiceBuilderFactory.php new file mode 100644 index 00000000..c7af145f --- /dev/null +++ b/src/Services/ServiceBuilderFactory.php @@ -0,0 +1,128 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services; + +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountInterface; +use Bitrix24\SDK\Core\Batch; +use Bitrix24\SDK\Core\BulkItemsReader\BulkItemsReaderBuilder; +use Bitrix24\SDK\Core\CoreBuilder; +use Bitrix24\SDK\Core\Credentials\AuthToken; +use Bitrix24\SDK\Core\Credentials\ApplicationProfile; +use Bitrix24\SDK\Core\Credentials\Credentials; +use Bitrix24\SDK\Core\Credentials\WebhookUrl; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Psr\Log\LoggerInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; + +class ServiceBuilderFactory +{ + private EventDispatcherInterface $eventDispatcher; + private LoggerInterface $log; + + /** + * @param EventDispatcherInterface $eventDispatcher + * @param LoggerInterface $log + */ + public function __construct(EventDispatcherInterface $eventDispatcher, LoggerInterface $log) + { + $this->eventDispatcher = $eventDispatcher; + $this->log = $log; + } + + /** + * Init service builder from application account + * + * @param ApplicationProfile $applicationProfile + * @param Bitrix24AccountInterface $bitrix24Account + * + * @return ServiceBuilder + * @throws InvalidArgumentException + */ + public function initFromAccount(ApplicationProfile $applicationProfile, Bitrix24AccountInterface $bitrix24Account): ServiceBuilder + { + return $this->getServiceBuilder( + Credentials::createFromOAuth( + $bitrix24Account->getAuthToken(), + $applicationProfile, + $bitrix24Account->getDomainUrl() + ) + ); + } + + /** + * Init service builder from request + * + * @param ApplicationProfile $applicationProfile + * @param AuthToken $accessToken + * @param string $bitrix24DomainUrl + * + * @return ServiceBuilder + * @throws InvalidArgumentException + */ + public function initFromRequest( + ApplicationProfile $applicationProfile, + AuthToken $accessToken, + string $bitrix24DomainUrl + ): ServiceBuilder + { + return $this->getServiceBuilder( + Credentials::createFromOAuth( + $accessToken, + $applicationProfile, + $bitrix24DomainUrl + ) + ); + } + + /** + * Init service builder from webhook + * + * @param string $webhookUrl + * + * @return ServiceBuilder + * @throws InvalidArgumentException + */ + public function initFromWebhook(string $webhookUrl): ServiceBuilder + { + return $this->getServiceBuilder(Credentials::createFromWebhook(new WebhookUrl($webhookUrl))); + } + + /** + * @param Credentials $credentials + * + * @return ServiceBuilder + * @throws InvalidArgumentException + */ + private function getServiceBuilder(Credentials $credentials): ServiceBuilder + { + $core = (new CoreBuilder()) + ->withEventDispatcher($this->eventDispatcher) + ->withLogger($this->log) + ->withCredentials($credentials) + ->build(); + $batch = new Batch($core, $this->log); + + return new ServiceBuilder( + $core, + $batch, + (new BulkItemsReaderBuilder( + $core, + $batch, + $this->log + ))->build(), + $this->log + ); + } + +} \ No newline at end of file diff --git a/src/Services/Telephony/Call/Result/TranscriptAttachItemResult.php b/src/Services/Telephony/Call/Result/TranscriptAttachItemResult.php new file mode 100644 index 00000000..3b60c3aa --- /dev/null +++ b/src/Services/Telephony/Call/Result/TranscriptAttachItemResult.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Call\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read non-negative-int $TRANSCRIPT_ID + */ +class TranscriptAttachItemResult extends AbstractItem +{ +} \ No newline at end of file diff --git a/src/Services/Telephony/Call/Result/TranscriptAttachedResult.php b/src/Services/Telephony/Call/Result/TranscriptAttachedResult.php new file mode 100644 index 00000000..4738bce6 --- /dev/null +++ b/src/Services/Telephony/Call/Result/TranscriptAttachedResult.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Call\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class TranscriptAttachedResult extends AbstractResult +{ + public function getTranscriptAttachItem(): TranscriptAttachItemResult + { + return new TranscriptAttachItemResult($this->getCoreResponse()->getResponseData()->getResult()); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Call/Service/Batch.php b/src/Services/Telephony/Call/Service/Batch.php new file mode 100644 index 00000000..19b02264 --- /dev/null +++ b/src/Services/Telephony/Call/Service/Batch.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Call\Service; + +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +use Psr\Log\LoggerInterface; + +readonly class Batch +{ + public function __construct( + protected BatchOperationsInterface $batch, + protected LoggerInterface $log) + { + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Call/Service/Call.php b/src/Services/Telephony/Call/Service/Call.php new file mode 100644 index 00000000..206f4308 --- /dev/null +++ b/src/Services/Telephony/Call/Service/Call.php @@ -0,0 +1,94 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Call\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Telephony\Call\Result\TranscriptAttachedResult; +use Bitrix24\SDK\Services\Telephony\Common\TranscriptMessage; +use Bitrix24\SDK\Services\Telephony\Call\Service\Batch; +use Money\Money; +use Psr\Log\LoggerInterface; +#[ApiServiceMetadata(new Scope(['telephony']))] +class Call extends AbstractService +{ + public function __construct( + readonly public Batch $batch, + CoreInterface $core, + LoggerInterface $logger + ) + { + parent::__construct($core, $logger); + } + + /** + * The method adds a call transcript. + * + * @param non-empty-string $callId + * @param TranscriptMessage[] $messages + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_call_attachtranscription.php + */ + #[ApiEndpointMetadata( + 'telephony.call.attachTranscription', + 'https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_call_attachtranscription.php', + 'The method adds a call transcript.' + )] + public function attachTranscription( + string $callId, + Money $money, + array $messages + ): TranscriptAttachedResult + { + $rawMessages = []; + foreach ($messages as $message) { + $rawMessages[] = [ + 'SIDE' => $message->side->value, + 'START_TIME' => $message->startTime, + 'STOP_TIME' => $message->stopTime, + 'MESSAGE' => $message->message + ]; + } + + return new TranscriptAttachedResult($this->core->call('telephony.call.attachTranscription', [ + 'CALL_ID' => $callId, + 'COST' => $this->decimalMoneyFormatter->format($money), + 'COST_CURRENCY' => $money->getCurrency()->getCode(), + 'MESSAGES' => $rawMessages + ])); + } +} + + + + + + + + + + + + + + + + + diff --git a/src/Services/Telephony/Common/CallFailedCode.php b/src/Services/Telephony/Common/CallFailedCode.php new file mode 100644 index 00000000..1d61285f --- /dev/null +++ b/src/Services/Telephony/Common/CallFailedCode.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Common; + +enum CallFailedCode: int +{ + case successful = 200; + case missed = 304; + case declined = 603; + case prohibited = 403; + case wrongNumber = 404; + case unavailable = 486; + case directionUnavailable = 484; + case directionUnavailableToo = 503; + case temporarilyUnavailable = 480; + case insufficientFundsOnTheAccount = 402; + case blocked = 423; +} \ 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..74c7e0fb --- /dev/null +++ b/src/Services/Telephony/Common/CallType.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Common; + +enum CallType: int +{ + case outbound = 1; + case inbound = 2; + case inboundWithRedirect = 3; + case callback = 4; +} diff --git a/src/Services/Telephony/Common/CrmEntity.php b/src/Services/Telephony/Common/CrmEntity.php new file mode 100644 index 00000000..537522bc --- /dev/null +++ b/src/Services/Telephony/Common/CrmEntity.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Common; + +readonly class CrmEntity +{ + public function __construct( + public int $id, + public CrmEntityType $type + ) + { + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Common/CrmEntityType.php b/src/Services/Telephony/Common/CrmEntityType.php new file mode 100644 index 00000000..4a34b6ff --- /dev/null +++ b/src/Services/Telephony/Common/CrmEntityType.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Common; + +enum CrmEntityType: string +{ + case contact = 'CONTACT'; + case company = 'COMPANY'; + case lead = 'LEAD'; +} diff --git a/src/Services/Telephony/Common/PbxType.php b/src/Services/Telephony/Common/PbxType.php new file mode 100644 index 00000000..b3233003 --- /dev/null +++ b/src/Services/Telephony/Common/PbxType.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Common; + +enum PbxType: string +{ + case cloud = 'cloud'; + case office = 'office'; +} \ No newline at end of file diff --git a/src/Services/Telephony/Common/SipRegistrationStatus.php b/src/Services/Telephony/Common/SipRegistrationStatus.php new file mode 100644 index 00000000..f4d10555 --- /dev/null +++ b/src/Services/Telephony/Common/SipRegistrationStatus.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Common; + +enum SipRegistrationStatus: string +{ + case success = 'success'; + case error = 'error'; + case inProgress = 'in_progress'; + case wait = 'wait'; +} \ No newline at end of file diff --git a/src/Services/Telephony/Common/TelephonyCallStatusCode.php b/src/Services/Telephony/Common/TelephonyCallStatusCode.php new file mode 100644 index 00000000..59aeb600 --- /dev/null +++ b/src/Services/Telephony/Common/TelephonyCallStatusCode.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Common; + +enum TelephonyCallStatusCode: int +{ + case successful = 200; + case missed = 304; + case prohibited = 403; + case declined = 603; + case wrong_number = 404; + case unavailable = 486; + case direction_unavailable = 484; + case direction_unavailable_too = 503; + case temporarily_unavailable = 480; + case insufficient_balance = 402; + case blocked = 423; +} diff --git a/src/Services/Telephony/Common/TranscriptMessage.php b/src/Services/Telephony/Common/TranscriptMessage.php new file mode 100644 index 00000000..ca71ac97 --- /dev/null +++ b/src/Services/Telephony/Common/TranscriptMessage.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Common; + +readonly class TranscriptMessage +{ + public function __construct( + public TranscriptMessageSide $side, + public int $startTime, + public int $stopTime, + public string $message + ) + { + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Common/TranscriptMessageSide.php b/src/Services/Telephony/Common/TranscriptMessageSide.php new file mode 100644 index 00000000..529fffd8 --- /dev/null +++ b/src/Services/Telephony/Common/TranscriptMessageSide.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Common; + +enum TranscriptMessageSide: string +{ + case user = 'User'; + case client = 'Client'; +} \ No newline at end of file diff --git a/src/Services/Telephony/Events/OnExternalCallBackStart/OnExternalCallBackStart.php b/src/Services/Telephony/Events/OnExternalCallBackStart/OnExternalCallBackStart.php new file mode 100644 index 00000000..57e23965 --- /dev/null +++ b/src/Services/Telephony/Events/OnExternalCallBackStart/OnExternalCallBackStart.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Events\OnExternalCallBackStart; + +use Bitrix24\SDK\Application\Requests\Events\AbstractEventRequest; + +class OnExternalCallBackStart extends AbstractEventRequest +{ + public const CODE = 'ONEXTERNALCALLBACKSTART'; + + public function getPayload(): OnExternalCallBackStartEventPayload + { + return new OnExternalCallBackStartEventPayload($this->eventPayload['data']); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Events/OnExternalCallBackStart/OnExternalCallBackStartEventPayload.php b/src/Services/Telephony/Events/OnExternalCallBackStart/OnExternalCallBackStartEventPayload.php new file mode 100644 index 00000000..4b36c9ed --- /dev/null +++ b/src/Services/Telephony/Events/OnExternalCallBackStart/OnExternalCallBackStartEventPayload.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Events\OnExternalCallBackStart; + +use Bitrix24\SDK\Core\Result\AbstractItem; +use Bitrix24\SDK\Services\Telephony\Common\CrmEntityType; + +/** + * @property-read non-empty-string $PHONE_NUMBER + * @property-read non-empty-string $TEXT + * @property-read non-empty-string $VOICE + * @property-read CrmEntityType $CRM_ENTITY_TYPE + * @property-read string $LINE_NUMBER + */ +class OnExternalCallBackStartEventPayload extends AbstractItem +{ + public function __get($offset) + { + return match ($offset) { + 'CRM_ENTITY_ID', => (int)$this->data[$offset], + 'CRM_ENTITY_TYPE' => CrmEntityType::from((string)$this->data[$offset]), + 'IS_MOBILE' => $this->data[$offset] !== '0', + default => $this->data[$offset] ?? null, + }; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Events/OnExternalCallStart/OnExternalCallStart.php b/src/Services/Telephony/Events/OnExternalCallStart/OnExternalCallStart.php new file mode 100644 index 00000000..f6a450d6 --- /dev/null +++ b/src/Services/Telephony/Events/OnExternalCallStart/OnExternalCallStart.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Events\OnExternalCallStart; + +use Bitrix24\SDK\Application\Requests\Events\AbstractEventRequest; + +class OnExternalCallStart extends AbstractEventRequest +{ + public const CODE = 'ONEXTERNALCALLSTART'; + + public function getPayload(): OnExternalCallStartEventPayload + { + return new OnExternalCallStartEventPayload($this->eventPayload['data']); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Events/OnExternalCallStart/OnExternalCallStartEventPayload.php b/src/Services/Telephony/Events/OnExternalCallStart/OnExternalCallStartEventPayload.php new file mode 100644 index 00000000..5e747e4c --- /dev/null +++ b/src/Services/Telephony/Events/OnExternalCallStart/OnExternalCallStartEventPayload.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Events\OnExternalCallStart; + +use Bitrix24\SDK\Core\Result\AbstractItem; +use Bitrix24\SDK\Services\Telephony\Common\CrmEntityType; + +/** + * @property-read non-empty-string $CALL_ID + * @property-read non-empty-string $PHONE_NUMBER + * @property-read non-empty-string $PHONE_NUMBER_INTERNATIONAL + * @property-read non-empty-string $LINE_NUMBER + * @property-read string $EXTENSION + * @property-read non-negative-int $USER_ID + * @property-read non-negative-int $CALL_LIST_ID + * @property-read non-negative-int $CRM_ENTITY_ID + * @property-read CrmEntityType $CRM_ENTITY_TYPE + * @property-read boolean $IS_MOBILE + * + */ +class OnExternalCallStartEventPayload extends AbstractItem +{ + public function __get($offset) + { + return match ($offset) { + 'USER_ID', 'CALL_LIST_ID', 'CRM_ENTITY_ID' => (int)$this->data[$offset], + 'CRM_ENTITY_TYPE' => CrmEntityType::from((string)$this->data[$offset]), + 'IS_MOBILE' => $this->data[$offset] !== '0', + default => $this->data[$offset] ?? null, + }; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Events/OnVoximplantCallEnd/OnVoximplantCallEnd.php b/src/Services/Telephony/Events/OnVoximplantCallEnd/OnVoximplantCallEnd.php new file mode 100644 index 00000000..0c8cc335 --- /dev/null +++ b/src/Services/Telephony/Events/OnVoximplantCallEnd/OnVoximplantCallEnd.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Events\OnVoximplantCallEnd; + +use Bitrix24\SDK\Application\Requests\Events\AbstractEventRequest; + +class +OnVoximplantCallEnd extends AbstractEventRequest +{ + public const CODE = 'ONVOXIMPLANTCALLEND'; +} \ No newline at end of file diff --git a/src/Services/Telephony/Events/OnVoximplantCallEnd/OnVoximplantCallEndEventPayload.php b/src/Services/Telephony/Events/OnVoximplantCallEnd/OnVoximplantCallEndEventPayload.php new file mode 100644 index 00000000..32f7dbd9 --- /dev/null +++ b/src/Services/Telephony/Events/OnVoximplantCallEnd/OnVoximplantCallEndEventPayload.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Events\OnVoximplantCallEnd; + +use Bitrix24\SDK\Core\Result\AbstractItem; +use Bitrix24\SDK\Services\Telephony\Common\CallFailedCode; +use Bitrix24\SDK\Services\Telephony\Common\CallType; +use Carbon\CarbonImmutable; +use Money\Currency; +use Money\Money; + +/** + * @property-read non-negative-int $CALL_DURATION + * @property-read CallFailedCode $CALL_FAILED_CODE + * @property-read ?string $CALL_FAILED_REASON + * @property-read non-empty-string $CALL_ID + * @property-read CarbonImmutable $CALL_START_DATE + * @property-read CallType $CALL_TYPE + * @property-read Currency $COST_CURRENCY + * @property-read Money $COST + * @property-read non-negative-int $CRM_ACTIVITY_ID + * @property-read non-empty-string $PHONE_NUMBER + * @property-read non-empty-string $PORTAL_NUMBER + * @property-read non-negative-int $PORTAL_USER_ID + * @link https://training.bitrix24.com/rest_help/scope_telephony/voximplant/events/onvoximplantcallend.php + */ +class OnVoximplantCallEndEventPayload extends AbstractItem +{ + public function __get($offset) + { + return match ($offset) { + 'CALL_DURATION', 'CRM_ACTIVITY_ID', 'PORTAL_USER_ID' => (int)$this->data[$offset], + 'CALL_FAILED_CODE' => CallFailedCode::from((int)$this->data[$offset]), + 'CALL_START_DATE' => CarbonImmutable::parse($this->data[$offset]), + 'CALL_TYPE' => CallType::from((int)$this->data[$offset]), + 'COST_CURRENCY' => new Currency((string)$this->data[$offset]), + 'COST' => $this->decimalMoneyParser->parse((string)$this->data[$offset], new Currency($this->data['COST_CURRENCY'])), + default => $this->data[$offset] ?? null, + }; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Events/OnVoximplantCallInit/OnVoximplantCallInit.php b/src/Services/Telephony/Events/OnVoximplantCallInit/OnVoximplantCallInit.php new file mode 100644 index 00000000..cc29ce27 --- /dev/null +++ b/src/Services/Telephony/Events/OnVoximplantCallInit/OnVoximplantCallInit.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Events\OnVoximplantCallInit; + +use Bitrix24\SDK\Application\Requests\Events\AbstractEventRequest; + +class OnVoximplantCallInit extends AbstractEventRequest +{ + public const CODE = 'ONVOXIMPLANTCALLINIT'; + + public function getPayload(): OnVoximplantCallInitEventPayload + { + return new OnVoximplantCallInitEventPayload($this->eventPayload['data']); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Events/OnVoximplantCallInit/OnVoximplantCallInitEventPayload.php b/src/Services/Telephony/Events/OnVoximplantCallInit/OnVoximplantCallInitEventPayload.php new file mode 100644 index 00000000..f9aad78c --- /dev/null +++ b/src/Services/Telephony/Events/OnVoximplantCallInit/OnVoximplantCallInitEventPayload.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Events\OnVoximplantCallInit; + +use Bitrix24\SDK\Core\Result\AbstractItem; +use Bitrix24\SDK\Services\Telephony\Common\CallType; + +/** + * @property-read non-empty-string $CALL_ID + * @property-read CallType $CALL_TYPE + * @property-read non-empty-string $CALLER_ID + * @property-read non-negative-int $REST_APP_ID + * @link https://training.bitrix24.com/rest_help/scope_telephony/voximplant/events/onvoximplantcallInit.php + */ +class OnVoximplantCallInitEventPayload extends AbstractItem +{ + public function __get($offset) + { + return match ($offset) { + 'USER_ID', 'REST_APP_ID' => (int)$this->data[$offset], + 'CALL_TYPE' => CallType::from((int)$this->data[$offset]), + default => $this->data[$offset] ?? null, + }; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Events/OnVoximplantCallStart/OnVoximplantCallStart.php b/src/Services/Telephony/Events/OnVoximplantCallStart/OnVoximplantCallStart.php new file mode 100644 index 00000000..a78c3586 --- /dev/null +++ b/src/Services/Telephony/Events/OnVoximplantCallStart/OnVoximplantCallStart.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Events\OnVoximplantCallStart; + +use Bitrix24\SDK\Application\Requests\Events\AbstractEventRequest; + +class OnVoximplantCallStart extends AbstractEventRequest +{ + public const CODE = 'ONVOXIMPLANTCALLSTART'; + + public function getPayload(): OnVoximplantCallStartEventPayload + { + return new OnVoximplantCallStartEventPayload($this->eventPayload['data']); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Events/OnVoximplantCallStart/OnVoximplantCallStartEventPayload.php b/src/Services/Telephony/Events/OnVoximplantCallStart/OnVoximplantCallStartEventPayload.php new file mode 100644 index 00000000..c67036b4 --- /dev/null +++ b/src/Services/Telephony/Events/OnVoximplantCallStart/OnVoximplantCallStartEventPayload.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Events\OnVoximplantCallStart; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read non-empty-string $CALL_ID + * @property-read int $USER_ID + * @link https://training.bitrix24.com/rest_help/scope_telephony/voximplant/events/onvoximplantcallstart.php + */ +class OnVoximplantCallStartEventPayload extends AbstractItem +{ + public function __get($offset) + { + return match ($offset) { + 'USER_ID' => (int)$this->data[$offset], + default => $this->data[$offset] ?? null, + }; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Events/TelephonyEventsFabric.php b/src/Services/Telephony/Events/TelephonyEventsFabric.php new file mode 100644 index 00000000..e19f2f44 --- /dev/null +++ b/src/Services/Telephony/Events/TelephonyEventsFabric.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + + +namespace Bitrix24\SDK\Services\Telephony\Events; + + +use Bitrix24\SDK\Application\Requests\Events\EventInterface; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Services\Telephony\Events\OnExternalCallBackStart\OnExternalCallBackStart; +use Bitrix24\SDK\Services\Telephony\Events\OnExternalCallStart\OnExternalCallStart; +use Bitrix24\SDK\Services\Telephony\Events\OnVoximplantCallEnd\OnVoximplantCallEnd; +use Bitrix24\SDK\Services\Telephony\Events\OnVoximplantCallInit\OnVoximplantCallInit; +use Bitrix24\SDK\Services\Telephony\Events\OnVoximplantCallStart\OnVoximplantCallStart; +use Symfony\Component\HttpFoundation\Request; + +readonly class TelephonyEventsFabric +{ + /** + * @throws InvalidArgumentException + */ + public function create(Request $request): ?EventInterface + { + $eventPayload = $request->request->all(); + if (!array_key_exists('event', $eventPayload)) { + throw new InvalidArgumentException('«event» key not found in event payload'); + } + + return match ($eventPayload['event']) { + OnExternalCallBackStart::CODE => new OnExternalCallBackStart($request), + OnExternalCallStart::CODE => new OnExternalCallStart($request), + OnVoximplantCallEnd::CODE => new OnVoximplantCallEnd($request), + OnVoximplantCallInit::CODE => new OnVoximplantCallInit($request), + OnVoximplantCallStart::CODE => new OnVoximplantCallStart($request), + default => null, + }; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/ExternalCall/Result/CallRecordFileUploadedItemResult.php b/src/Services/Telephony/ExternalCall/Result/CallRecordFileUploadedItemResult.php new file mode 100644 index 00000000..9c516464 --- /dev/null +++ b/src/Services/Telephony/ExternalCall/Result/CallRecordFileUploadedItemResult.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\ExternalCall\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read int $FILE_ID + */ +class CallRecordFileUploadedItemResult extends AbstractItem +{ +} \ No newline at end of file diff --git a/src/Services/Telephony/ExternalCall/Result/CallRecordFileUploadedResult.php b/src/Services/Telephony/ExternalCall/Result/CallRecordFileUploadedResult.php new file mode 100644 index 00000000..ea448047 --- /dev/null +++ b/src/Services/Telephony/ExternalCall/Result/CallRecordFileUploadedResult.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\ExternalCall\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class CallRecordFileUploadedResult extends AbstractResult +{ + public function getRecordUploadedResult(): CallRecordFileUploadedItemResult + { + return new CallRecordFileUploadedItemResult($this->getCoreResponse()->getResponseData()->getResult()); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/ExternalCall/Result/CallRecordUploadUrlItemResult.php b/src/Services/Telephony/ExternalCall/Result/CallRecordUploadUrlItemResult.php new file mode 100644 index 00000000..1c6524de --- /dev/null +++ b/src/Services/Telephony/ExternalCall/Result/CallRecordUploadUrlItemResult.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\ExternalCall\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read non-empty-string $uploadUrl + * @property-read non-empty-string $fieldName + */ +class CallRecordUploadUrlItemResult extends AbstractItem +{ +} \ No newline at end of file diff --git a/src/Services/Telephony/ExternalCall/Result/CallRecordUploadUrlResult.php b/src/Services/Telephony/ExternalCall/Result/CallRecordUploadUrlResult.php new file mode 100644 index 00000000..566385c6 --- /dev/null +++ b/src/Services/Telephony/ExternalCall/Result/CallRecordUploadUrlResult.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\ExternalCall\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class CallRecordUploadUrlResult extends AbstractResult +{ + public function getUploadUrlResult(): CallRecordUploadUrlItemResult + { + return new CallRecordUploadUrlItemResult($this->getCoreResponse()->getResponseData()->getResult()); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/ExternalCall/Result/ExternalCallFinishedItemResult.php b/src/Services/Telephony/ExternalCall/Result/ExternalCallFinishedItemResult.php new file mode 100644 index 00000000..64e0d5cf --- /dev/null +++ b/src/Services/Telephony/ExternalCall/Result/ExternalCallFinishedItemResult.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\ExternalCall\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; +use Bitrix24\SDK\Services\Telephony\Common\CrmEntity; +use Bitrix24\SDK\Services\Telephony\Common\CrmEntityType; +use Money\Currency; +use Money\Money; + +/** + * @property-read string $CALL_ID Call ID inside Bitrix24. + * @property-read string|null $EXTERNAL_CALL_ID + * @property-read int $PORTAL_USER_ID + * @property-read string $PHONE_NUMBER + * @property-read string $PORTAL_NUMBER + * @property-read bool $INCOMING + * @property-read int $CALL_DURATION + * @property-read array $CALL_START_DATE + * @property-read int $CALL_STATUS + * @property-read int $CALL_VOTE + * @property-read Money $COST + * @property-read Currency $COST_CURRENCY + * @property-read int $CALL_FAILED_CODE + * @property-read string $CALL_FAILED_REASON + * @property-read string $REST_APP_ID + * @property-read bool $REST_APP_NAME + * @property-read int $CRM_ACTIVITY_ID + * @property-read string|null $COMMENT + * @property-read CrmEntityType $CRM_ENTITY_TYPE + * @property-read int $CRM_ENTITY_ID + * @property-read int $ID + */ +class ExternalCallFinishedItemResult extends AbstractItem +{ + public function __get($offset) + { + switch ($offset) { + case 'COST': + return $this->decimalMoneyParser->parse((string)$this->data[$offset], new Currency($this->data['COST_CURRENCY'])); + case 'COST_CURRENCY': + return new Currency($this->data[$offset]); + case 'INCOMING': + return $this->data[$offset] === '1'; + case 'PORTAL_USER_ID': + case 'CALL_STATUS': + case 'CALL_VOTE': + case 'CALL_FAILED_CODE': + case 'CRM_ACTIVITY_ID': + case 'CRM_ENTITY_ID': + case 'ID': + return (int)$this->data[$offset]; + case'CRM_ENTITY_TYPE': + return CrmEntityType::from($this->data[$offset]); + case 'CRM_CREATED_ENTITIES': + $res = []; + foreach ($this->data[$offset] as $item) { + $res[] = new CrmEntity( + (int)$item['ENTITY_ID'], + CrmEntityType::from($item['ENTITY_TYPE']) + ); + } + + return $res; + default: + return $this->data[$offset] ?? null; + } + } +} \ No newline at end of file diff --git a/src/Services/Telephony/ExternalCall/Result/ExternalCallFinishedResult.php b/src/Services/Telephony/ExternalCall/Result/ExternalCallFinishedResult.php new file mode 100644 index 00000000..b6baae82 --- /dev/null +++ b/src/Services/Telephony/ExternalCall/Result/ExternalCallFinishedResult.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\ExternalCall\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class ExternalCallFinishedResult extends AbstractResult +{ + public function getExternalCallFinished(): ExternalCallFinishedItemResult + { + return new ExternalCallFinishedItemResult($this->getCoreResponse()->getResponseData()->getResult()); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/ExternalCall/Result/ExternalCallRegisteredItemResult.php b/src/Services/Telephony/ExternalCall/Result/ExternalCallRegisteredItemResult.php new file mode 100644 index 00000000..1bfb63c0 --- /dev/null +++ b/src/Services/Telephony/ExternalCall/Result/ExternalCallRegisteredItemResult.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\ExternalCall\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; +use Bitrix24\SDK\Services\Telephony\Common\CrmEntity; +use Bitrix24\SDK\Services\Telephony\Common\CrmEntityType; + +/** + * @property-read string $CALL_ID Call ID inside Bitrix24. + * @property-read ?int $CRM_CREATED_LEAD Created lead ID (is created, if the object is not found in CRM by the incoming number) + * @property-read CrmEntity[] $CRM_CREATED_ENTITIES Array with entities automatically created in CRM when registering a call. + * @property-read CrmEntityType $CRM_ENTITY_TYPE Type of the object found in CRM by the incoming number CONTACT | COMPANY | LEAD. + * @property-read ?int $CRM_ENTITY_ID ID of the object found in CRM. + * @property-read string $LEAD_CREATION_ERROR Error text, occurring when creating a lead in CRM. + */ +class ExternalCallRegisteredItemResult extends AbstractItem +{ + public function __get($offset) + { + switch ($offset) { + case'CRM_ENTITY_TYPE': + return CrmEntityType::from($this->data[$offset]); + case 'CRM_CREATED_ENTITIES': + $res = []; + foreach ($this->data[$offset] as $item) { + $res[] = new CrmEntity( + (int)$item['ENTITY_ID'], + CrmEntityType::from($item['ENTITY_TYPE']) + ); + } + + return $res; + default: + return $this->data[$offset] ?? null; + } + } + + public function isError(): bool + { + if (!$this->isKeyExists('LEAD_CREATION_ERROR')) { + return false; + } + + return $this->data['LEAD_CREATION_ERROR'] !== '' && $this->data['LEAD_CREATION_ERROR'] !== null; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/ExternalCall/Result/ExternalCallRegisteredResult.php b/src/Services/Telephony/ExternalCall/Result/ExternalCallRegisteredResult.php new file mode 100644 index 00000000..72d84f7f --- /dev/null +++ b/src/Services/Telephony/ExternalCall/Result/ExternalCallRegisteredResult.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\ExternalCall\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class ExternalCallRegisteredResult extends AbstractResult +{ + public function getExternalCallRegistered(): ExternalCallRegisteredItemResult + { + return new ExternalCallRegisteredItemResult($this->getCoreResponse()->getResponseData()->getResult()); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/ExternalCall/Result/SearchCrmEntitiesItemResult.php b/src/Services/Telephony/ExternalCall/Result/SearchCrmEntitiesItemResult.php new file mode 100644 index 00000000..ad65555d --- /dev/null +++ b/src/Services/Telephony/ExternalCall/Result/SearchCrmEntitiesItemResult.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\ExternalCall\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; +use Bitrix24\SDK\Services\Telephony\Common\CrmEntityType; + +/** + * @property-read CrmEntityType $CRM_ENTITY_TYPE + * @property-read int $CRM_ENTITY_ID + * @property-read int $ASSIGNED_BY_ID + * @property-read string $NAME + * @property-read UserDigestItemResult $ASSIGNED_BY + */ +class SearchCrmEntitiesItemResult extends AbstractItem +{ + public function __get($offset) + { + return match ($offset) { + 'CRM_ENTITY_TYPE' => CrmEntityType::from($this->data[$offset]), + 'CRM_ENTITY_ID', 'ASSIGNED_BY_ID' => (int)$this->data[$offset], + 'ASSIGNED_BY' => new UserDigestItemResult($this->data[$offset]), + default => $this->data[$offset] ?? null, + }; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/ExternalCall/Result/SearchCrmEntitiesResult.php b/src/Services/Telephony/ExternalCall/Result/SearchCrmEntitiesResult.php new file mode 100644 index 00000000..8034e77e --- /dev/null +++ b/src/Services/Telephony/ExternalCall/Result/SearchCrmEntitiesResult.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\ExternalCall\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class SearchCrmEntitiesResult extends AbstractResult +{ + /** + * @return SearchCrmEntitiesItemResult[] + * @throws BaseException + */ + public function getCrmEntities(): array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { + $res[] = new SearchCrmEntitiesItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/ExternalCall/Result/UserDigestItemResult.php b/src/Services/Telephony/ExternalCall/Result/UserDigestItemResult.php new file mode 100644 index 00000000..d74ff7b5 --- /dev/null +++ b/src/Services/Telephony/ExternalCall/Result/UserDigestItemResult.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\ExternalCall\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read int $ID + * @property-read string $TIMEMAN_STATUS + * @property-read string $USER_PHONE_INNER + * @property-read string $WORK_PHONE + * @property-read string $PERSONAL_PHONE + * @property-read string $PERSONAL_MOBILE + * + */ +class UserDigestItemResult extends AbstractItem +{ + public function __get($offset) + { + return match ($offset) { + 'ID' => (int)$this->data[$offset], + default => $this->data[$offset] ?? null, + }; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/ExternalCall/Service/Batch.php b/src/Services/Telephony/ExternalCall/Service/Batch.php new file mode 100644 index 00000000..3e9a4956 --- /dev/null +++ b/src/Services/Telephony/ExternalCall/Service/Batch.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\ExternalCall\Service; + +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +use Psr\Log\LoggerInterface; + +readonly class Batch +{ + public function __construct( + protected BatchOperationsInterface $batch, + protected LoggerInterface $log) + { + } +} \ No newline at end of file diff --git a/src/Services/Telephony/ExternalCall/Service/ExternalCall.php b/src/Services/Telephony/ExternalCall/Service/ExternalCall.php new file mode 100644 index 00000000..b7ca7d6d --- /dev/null +++ b/src/Services/Telephony/ExternalCall/Service/ExternalCall.php @@ -0,0 +1,355 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\ExternalCall\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\FileNotFoundException; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult; +use Bitrix24\SDK\Infrastructure\Filesystem\Base64Encoder; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Telephony\Common\CallType; +use Bitrix24\SDK\Services\Telephony\Common\CrmEntityType; +use Bitrix24\SDK\Services\Telephony\Common\TelephonyCallStatusCode; +use Bitrix24\SDK\Services\Telephony\ExternalCall\Result\CallRecordFileUploadedResult; +use Bitrix24\SDK\Services\Telephony\ExternalCall\Result\CallRecordUploadUrlResult; +use Bitrix24\SDK\Services\Telephony\ExternalCall\Result\ExternalCallFinishedResult; +use Bitrix24\SDK\Services\Telephony\ExternalCall\Result\ExternalCallRegisteredResult; +use Bitrix24\SDK\Services\Telephony\ExternalCall\Result\SearchCrmEntitiesResult; +use Carbon\CarbonImmutable; +use Money\Money; +use Psr\Log\LoggerInterface; + +#[ApiServiceMetadata(new Scope(['telephony']))] +class ExternalCall extends AbstractService +{ + public function __construct( + readonly public Batch $batch, + private readonly Base64Encoder $base64Encoder, + CoreInterface $core, + LoggerInterface $logger + ) + { + parent::__construct($core, $logger); + } + + /** + * Get url for upload call record + * + * @param non-empty-string $callId + * @param non-empty-string $callRecordFileName + * @throws BaseException + * @throws InvalidArgumentException + * @throws TransportException + * @throws FileNotFoundException + * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalCall_attachRecord.php + */ + #[ApiEndpointMetadata( + 'telephony.externalCall.attachRecord', + 'https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalCall_attachRecord.php', + 'Get url for upload call record' + )] + public function getCallRecordUploadUrl( + string $callId, + string $callRecordFileName, + ): CallRecordUploadUrlResult + { + return new CallRecordUploadUrlResult($this->core->call('telephony.externalCall.attachRecord', [ + 'CALL_ID' => $callId, + 'FILENAME' => pathinfo($callRecordFileName, PATHINFO_BASENAME), + 'FILE_CONTENT' => null + ])); + } + + /** + * This method connects a record to a finished call and to the call Activity. + * + * @param non-empty-string $callId + * @param non-empty-string $callRecordFileName + * @throws BaseException + * @throws InvalidArgumentException + * @throws TransportException + * @throws FileNotFoundException + * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalCall_attachRecord.php + */ + #[ApiEndpointMetadata( + 'telephony.externalCall.attachRecord', + 'https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalCall_attachRecord.php', + 'This method connects a record to a finished call and to the call Activity.' + )] + public function attachCallRecordInBase64( + string $callId, + string $callRecordFileName, + ): CallRecordFileUploadedResult + { + return new CallRecordFileUploadedResult($this->core->call('telephony.externalCall.attachRecord', [ + 'CALL_ID' => $callId, + // we need unique uploaded filename + 'FILENAME' => sprintf('%s-%s', time(), pathinfo($callRecordFileName, PATHINFO_BASENAME)), + 'FILE_CONTENT' => $this->base64Encoder->encodeCallRecord($callRecordFileName) + ])); + } + + /** + * Method registers a call in Bitrix24. For this purpose, it searches an object that corresponds to the number in CRM. + * + * If the method finds it, it adds the call, connected to the object found. If the method didn't find it, it can create a lead automatically. + * + * First user previously responsible for this customer is assigned as the responsible for a new lead automatically when using telephony.externalCall.register. + * You subsequently can change such responsible user via telephony.externalcall.finish. + * Simultaneously with the registration of a call, method optionally can show the user the call ID screen. + * The user that views the displayed call pane, is identified either by USER_ID or by USER_PHONE_INNER. + * (That is, fields are marked as required, but actually, only one of two is required). + * + * No need to repeatedly call this method for call received at the event OnExternalCallStart. + * Such calls have been registered already in the system and you need to only call telephony.externalcall.finish when call finishes. + * + * Attention! Repeated call telephony.externalcall.register with the same parameters, without closing the previous + * call by the method telephony.externalcall.finish - fetches the same CALL_ID during 30 minutes. + * + * To create a call "activity", it is also necessary to call the telephony.externalcall.finish method + * + * @param non-empty-string $userInnerPhoneNumber Internal number of the user. Required. + * @param non-negative-int $b24UserId User ID. Required. + * @param non-empty-string $phoneNumber Telephone number. Required + * @param CarbonImmutable $callStartDate Date/time of the call in the ISO8601 format. Please note, that the date must pass an hour zone, to avoid confusing call time + * @param CallType $callType Type of call: + * 1 - outbound + * 2 - inbound + * 3 - inbound with forwarding + * 4 - callback + * @param bool $isShowCallCard Option to display or not the call ID screen + * @param bool|null $isCreateCrmEntities Automatic creating of CRM entity associated with a call. + * If required, creates a lead or deal in CRM, depending on settings and performance CRM mode. + * Please note, a deal activity is created with any value of this parameter, if possible. + * @param non-empty-string|null $lineNumber Number of external line, via which the call was made (see. telephony.externalLine.add). Optional. + * @param non-empty-string|null $sourceId STATUS_ID of the source from the source selection list. + * You can receive a list of sources by the crm.status.list method with filter by "ENTITY_ID": "SOURCE" + * @param CrmEntityType|null $crmEntityType Type of CRM object, from the details card of which the call is made - CONTACT | COMPANY | LEAD. + * @param int|null $crmEntityId CRM object ID, type of which is specified in CRM_ENTITY_TYPE + * @param int|null $callListId Call dialing list ID, to which the call should be connected. + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_register.php + */ + #[ApiEndpointMetadata( + 'telephony.externalcall.register', + 'https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_register.php', + 'Method registers a call in Bitrix24. For this purpose, it searches an object that corresponds to the number in CRM.' + )] + public function register( + string $userInnerPhoneNumber, + int $b24UserId, + string $phoneNumber, + CarbonImmutable $callStartDate, + CallType $callType, + bool $isShowCallCard = true, + ?bool $isCreateCrmEntities = null, + ?string $lineNumber = null, + ?string $sourceId = null, + ?CrmEntityType $crmEntityType = null, + ?int $crmEntityId = null, + ?int $callListId = null, + ): ExternalCallRegisteredResult + { + return new ExternalCallRegisteredResult( + $this->core->call('telephony.externalcall.register', + [ + 'USER_PHONE_INNER' => $userInnerPhoneNumber, + 'USER_ID' => $b24UserId, + 'PHONE_NUMBER' => $phoneNumber, + 'CALL_START_DATE' => $callStartDate->format(DATE_ATOM), + 'CRM_CREATE' => $isCreateCrmEntities === true ? 1 : 0, + 'CRM_SOURCE' => $sourceId, + 'CRM_ENTITY_TYPE' => $crmEntityType?->value, + 'CRM_ENTITY_ID' => $crmEntityId, + 'SHOW' => $isShowCallCard ? 1 : 0, + 'CALL_LIST_ID' => $callListId, + 'LINE_NUMBER' => $lineNumber, + 'TYPE' => $callType->value, + ]) + ); + } + + /** + * This method allows to retrieve information about a client from CRM by a telephone number via single request. + * + * This method allows to retrieve information about a client from CRM by a telephone number via single request. + * This information allows to make a decision, to which employee the inbound call shall be forwarded to at the very moment of the call. + * This method returns a suitable list of CRM objects with sorting by internal priorities. + * If different employees are responsible for entities, linked with the number (one employee is responsible for a lead, + * and another employee is responsible for a company), then it is recommended to select the object, + * which was returned by the method as the first in the list. If integration has its own logic, then a selection is possible, + * because all the objects are transferred. + * + * All information about an employee, responsible for each object is provided right away in the list of CRM objects + * (so that there is no necessity to retrieve this information via additional REST requests). All contact phone numbers + * specified for a user are returned: internal telephone number for an employee, work office and etc. + * + * An employee workday status is also returned (if work time management feature is enabled in the user's Bitrix24 account). + * The integration can check, whether an employee is located at the workplace at the moment (or he/she is having a lunchtime break), + * or it can forward a phone call to a queue, or forward a call to a mobile phone of an employee and etc. + * + * It is recommended to call this method prior to calling the telephony.externalcall.register method. + * + * @param non-empty-string $phoneNumber + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'telephony.externalCall.searchCrmEntities', + 'https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalCall_searchCrmEntities.php', + 'This method allows to retrieve information about a client from CRM by a telephone number via single request.' + )] + public function searchCrmEntities(string $phoneNumber): SearchCrmEntitiesResult + { + return new SearchCrmEntitiesResult($this->core->call('telephony.externalCall.searchCrmEntities', + [ + 'PHONE_NUMBER' => $phoneNumber + ])); + } + + /** + * Method completes the call, registers it in the statistics and hides the call ID screen from the user. + * + * @param non-empty-string $callId + * @param non-empty-string $userInnerPhoneNumber + * @param non-negative-int $duration + * @param non-empty-string|null $failedReason + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_finish.php + */ + #[ApiEndpointMetadata( + 'telephony.externalcall.finish', + 'https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_finish.php', + 'This method allows to retrieve information about a client from CRM by a telephone number via single request.' + )] + public function finishForUserPhoneInner( + string $callId, + string $userInnerPhoneNumber, + int $duration, + Money $money, + TelephonyCallStatusCode $telephonyCallStatusCode, + bool $isAddCallToChat = false, + ?string $failedReason = null, + ?int $userVote = null, + ): ExternalCallFinishedResult + { + return new ExternalCallFinishedResult($this->core->call('telephony.externalcall.finish', + [ + 'CALL_ID' => $callId, + 'USER_ID' => $userInnerPhoneNumber, + 'DURATION' => $duration, + 'COST' => $this->decimalMoneyFormatter->format($money), + 'COST_CURRENCY' => $money->getCurrency()->getCode(), + 'STATUS_CODE' => $telephonyCallStatusCode->value, + 'FAILED_REASON' => $failedReason, + 'VOTE' => $userVote, + 'ADD_TO_CHAT' => $isAddCallToChat ? 1 : 0 + ])); + } + + /** + * Method completes the call, registers it in the statistics and hides the call ID screen from the user. + * + * @param non-empty-string $callId + * @param positive-int $b24UserId + * @param non-negative-int $duration + * @param non-empty-string|null $failedReason + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_finish.php + */ + #[ApiEndpointMetadata( + 'telephony.externalcall.finish', + 'https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_finish.php', + 'This method allows to retrieve information about a client from CRM by a telephone number via single request.' + )] + public function finishForUserId( + string $callId, + int $b24UserId, + int $duration, + Money $money, + TelephonyCallStatusCode $telephonyCallStatusCode, + bool $isAddCallToChat = false, + ?string $failedReason = null, + ?int $userVote = null, + ): ExternalCallFinishedResult + { + return new ExternalCallFinishedResult($this->core->call('telephony.externalcall.finish', + [ + 'CALL_ID' => $callId, + 'USER_ID' => $b24UserId, + 'DURATION' => $duration, + 'COST' => $this->decimalMoneyFormatter->format($money), + 'COST_CURRENCY' => $money->getCurrency()->getCode(), + 'STATUS_CODE' => $telephonyCallStatusCode->value, + 'FAILED_REASON' => $failedReason, + 'VOTE' => $userVote, + 'ADD_TO_CHAT' => $isAddCallToChat ? 1 : 0 + ])); + } + + /** + * The method displays a call ID screen to the user. + * + * @param non-empty-string $callId + * @param array $b24UserId + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_show.php + */ + #[ApiEndpointMetadata( + 'telephony.externalcall.show', + 'https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_show.php', + 'The method displays a call ID screen to the user.' + )] + public function show(string $callId, array $b24UserId): UserInterfaceDialogCallResult + { + return new UserInterfaceDialogCallResult($this->core->call('telephony.externalcall.show', + [ + 'CALL_ID' => $callId, + 'USER_ID' => $b24UserId + ])); + } + + /** + * This method hides call information window. + * + * @param non-empty-string $callId + * @param array $b24UserId + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_hide.php + */ + #[ApiEndpointMetadata( + 'telephony.externalcall.hide', + 'https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_hide.php', + ' This method hides call information window.' + )] + public function hide(string $callId, array $b24UserId): UserInterfaceDialogCallResult + { + return new UserInterfaceDialogCallResult($this->core->call('telephony.externalcall.hide', + [ + 'CALL_ID' => $callId, + 'USER_ID' => $b24UserId + ])); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/ExternalLine/Result/ExternalLineAddItemResult.php b/src/Services/Telephony/ExternalLine/Result/ExternalLineAddItemResult.php new file mode 100644 index 00000000..34cfe9d8 --- /dev/null +++ b/src/Services/Telephony/ExternalLine/Result/ExternalLineAddItemResult.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\ExternalLine\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read non-negative-int $ID + */ +class ExternalLineAddItemResult extends AbstractItem +{ +} \ No newline at end of file diff --git a/src/Services/Telephony/ExternalLine/Result/ExternalLineAddedResult.php b/src/Services/Telephony/ExternalLine/Result/ExternalLineAddedResult.php new file mode 100644 index 00000000..08755af2 --- /dev/null +++ b/src/Services/Telephony/ExternalLine/Result/ExternalLineAddedResult.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\ExternalLine\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class ExternalLineAddedResult extends AbstractResult +{ + public function getExternalLineAddResultItem(): ExternalLineAddItemResult + { + return new ExternalLineAddItemResult($this->getCoreResponse()->getResponseData()->getResult()); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/ExternalLine/Result/ExternalLineItemResult.php b/src/Services/Telephony/ExternalLine/Result/ExternalLineItemResult.php new file mode 100644 index 00000000..24f3e585 --- /dev/null +++ b/src/Services/Telephony/ExternalLine/Result/ExternalLineItemResult.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\ExternalLine\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read non-empty-string $NUMBER + * @property-read non-empty-string|null $NAME + * @property-read bool $CRM_AUTO_CREATE + */ +class ExternalLineItemResult extends AbstractItem +{ + public function __get($offset) + { + return match ($offset) { + 'CRM_AUTO_CREATE' => $this->data[$offset] === 'Y', + default => $this->data[$offset] ?? null, + }; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/ExternalLine/Result/ExternalLinesResult.php b/src/Services/Telephony/ExternalLine/Result/ExternalLinesResult.php new file mode 100644 index 00000000..24620127 --- /dev/null +++ b/src/Services/Telephony/ExternalLine/Result/ExternalLinesResult.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\ExternalLine\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class ExternalLinesResult extends AbstractResult +{ + public function getExternalLines(): array + { + $lines = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $line) { + $lines[] = new ExternalLineItemResult($line); + } + + return $lines; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/ExternalLine/Service/Batch.php b/src/Services/Telephony/ExternalLine/Service/Batch.php new file mode 100644 index 00000000..7f747eed --- /dev/null +++ b/src/Services/Telephony/ExternalLine/Service/Batch.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\ExternalLine\Service; + +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +use Psr\Log\LoggerInterface; + +readonly class Batch +{ + public function __construct( + protected BatchOperationsInterface $batch, + protected LoggerInterface $log) + { + } +} \ No newline at end of file diff --git a/src/Services/Telephony/ExternalLine/Service/ExternalLine.php b/src/Services/Telephony/ExternalLine/Service/ExternalLine.php new file mode 100644 index 00000000..1156b3e9 --- /dev/null +++ b/src/Services/Telephony/ExternalLine/Service/ExternalLine.php @@ -0,0 +1,99 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\ExternalLine\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\EmptyResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Telephony\ExternalLine\Result\ExternalLineAddedResult; +use Bitrix24\SDK\Services\Telephony\ExternalLine\Result\ExternalLinesResult; +use Psr\Log\LoggerInterface; +#[ApiServiceMetadata(new Scope(['telephony']))] +class ExternalLine extends AbstractService +{ + public function __construct( + readonly public Batch $batch, + CoreInterface $core, + LoggerInterface $logger + ) + { + parent::__construct($core, $logger); + } + + /** + * Method adds an external line + * + * @param non-empty-string $lineNumber Number of the external line (For example: 8-9938-832799312) + * @param bool $isAutoCreateCrmEntities This parameter is responsible for creating CRM entities (deal or lead, depending on the CRM mode) + * for outbound calls from Bitrix24 interface (for example, dialer in chat panel). Default value is true + * @param non-empty-string|null $lineName Name of the external line. Optional. + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalLine_add.php + */ + #[ApiEndpointMetadata( + 'telephony.externalLine.add', + 'https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalLine_add.php', + 'Method adds an external line' + )] + public function add(string $lineNumber, bool $isAutoCreateCrmEntities = true, ?string $lineName = null): ExternalLineAddedResult + { + return new ExternalLineAddedResult($this->core->call('telephony.externalLine.add', [ + 'NUMBER' => $lineNumber, + 'NAME' => $lineName, + 'CRM_AUTO_CREATE' => $isAutoCreateCrmEntities ? 'Y' : 'N' + ])); + } + + /** + * Method for deleting an external line. + * + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalLine_delete.php + */ + #[ApiEndpointMetadata( + 'telephony.externalLine.delete', + 'https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalLine_delete.php', + 'Method for deleting an external line.' + )] + public function delete(string $lineNumber): EmptyResult + { + return new EmptyResult($this->core->call('telephony.externalLine.delete', [ + 'NUMBER' => $lineNumber + ])); + } + + /** + * Method allows to retrieve the list of external lines of an application. + * + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalLine_get.php + */ + #[ApiEndpointMetadata( + 'telephony.externalLine.get', + 'https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalLine_delete.php', + 'Method allows to retrieve the list of external lines of an application.' + )] + public function get(): ExternalLinesResult + { + return new ExternalLinesResult($this->core->call('telephony.externalLine.get')); + } +} \ 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..6d872b31 --- /dev/null +++ b/src/Services/Telephony/TelephonyServiceBuilder.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony; + +use Bitrix24\SDK\Infrastructure\Filesystem\Base64Encoder; +use Bitrix24\SDK\Services\AbstractServiceBuilder; +use Bitrix24\SDK\Services\Telephony; +use Symfony\Component\Filesystem\Filesystem; + +class TelephonyServiceBuilder extends AbstractServiceBuilder +{ + public function externalCall(): Telephony\ExternalCall\Service\ExternalCall + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Telephony\ExternalCall\Service\ExternalCall( + new Telephony\ExternalCall\Service\Batch($this->batch, $this->log), + new Base64Encoder( + new Filesystem(), + new \Symfony\Component\Mime\Encoder\Base64Encoder(), + $this->log, + ), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + + public function call(): Telephony\Call\Service\Call + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Telephony\Call\Service\Call( + new Telephony\Call\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + + public function externalLine(): Telephony\ExternalLine\Service\ExternalLine + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Telephony\ExternalLine\Service\ExternalLine( + new Telephony\ExternalLine\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + + public function getVoximplantServiceBuilder(): Telephony\Voximplant\VoximplantServiceBuilder + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Telephony\Voximplant\VoximplantServiceBuilder( + $this->core, + $this->batch, + $this->bulkItemsReader, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/InfoCall/Result/VoximplantInfoCallItemResult.php b/src/Services/Telephony/Voximplant/InfoCall/Result/VoximplantInfoCallItemResult.php new file mode 100644 index 00000000..44105010 --- /dev/null +++ b/src/Services/Telephony/Voximplant/InfoCall/Result/VoximplantInfoCallItemResult.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\InfoCall\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read non-empty-string $CALL_ID + * @property-read bool $RESULT + */ +class VoximplantInfoCallItemResult extends AbstractItem +{ +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/InfoCall/Result/VoximplantInfoCallResult.php b/src/Services/Telephony/Voximplant/InfoCall/Result/VoximplantInfoCallResult.php new file mode 100644 index 00000000..f84fe59e --- /dev/null +++ b/src/Services/Telephony/Voximplant/InfoCall/Result/VoximplantInfoCallResult.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\InfoCall\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class VoximplantInfoCallResult extends AbstractResult +{ + public function getCallResult(): VoximplantInfoCallItemResult + { + return new VoximplantInfoCallItemResult($this->getCoreResponse()->getResponseData()->getResult()); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/InfoCall/Service/Batch.php b/src/Services/Telephony/Voximplant/InfoCall/Service/Batch.php new file mode 100644 index 00000000..40f1dec5 --- /dev/null +++ b/src/Services/Telephony/Voximplant/InfoCall/Service/Batch.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\InfoCall\Service; + +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +use Psr\Log\LoggerInterface; + +readonly class Batch +{ + public function __construct( + protected BatchOperationsInterface $batch, + protected LoggerInterface $log) + { + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/InfoCall/Service/InfoCall.php b/src/Services/Telephony/Voximplant/InfoCall/Service/InfoCall.php new file mode 100644 index 00000000..74a0e9a4 --- /dev/null +++ b/src/Services/Telephony/Voximplant/InfoCall/Service/InfoCall.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\InfoCall\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\AbstractService; + +use Bitrix24\SDK\Services\Telephony\Voximplant\InfoCall\Result\VoximplantInfoCallResult; +use Psr\Log\LoggerInterface; +#[ApiServiceMetadata(new Scope(['telephony']))] +class InfoCall extends AbstractService +{ + public function __construct( + readonly public Batch $batch, + CoreInterface $core, + LoggerInterface $logger + ) + { + parent::__construct($core, $logger); + } + + /** + * method performs the call to the specified number with automatic voiceover of specified text + * + * method available the user with granted access permission for the Outbound call - Action - Any. + * + * @param non-empty-string $lineId + * @param non-empty-string $toNumber + * @param non-empty-string $text + * @param non-empty-string|null $voiceCode + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_infocall_startwithtext.php + */ + #[ApiEndpointMetadata( + 'voximplant.infocall.startwithtext', + 'https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_infocall_startwithtext.php', + 'method performs the call to the specified number with automatic voiceover of specified text' + )] + public function startWithText(string $lineId, string $toNumber, string $text, ?string $voiceCode = null): VoximplantInfoCallResult + { + return new VoximplantInfoCallResult($this->core->call('voximplant.infocall.startwithtext', [ + 'FROM_LINE' => $lineId, + 'TO_NUMBER' => $toNumber, + 'TEXT_TO_PRONOUNCE' => $text, + 'VOICE' => $voiceCode + ])); + } + + #[ApiEndpointMetadata( + 'voximplant.infocall.startwithsound', + 'https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_infocall_startwithsound.php', + 'Makes a call to the specified number with playback of .mp3 format file by URL.' + )] + public function startWithSound(string $lineId, string $toNumber, string $recordUrl): VoximplantInfoCallResult + { + return new VoximplantInfoCallResult($this->core->call('voximplant.infocall.startwithsound', [ + 'FROM_LINE' => $lineId, + 'TO_NUMBER' => $toNumber, + 'URL' => $recordUrl + ])); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/Line/Result/VoximplantLineIdItemResult.php b/src/Services/Telephony/Voximplant/Line/Result/VoximplantLineIdItemResult.php new file mode 100644 index 00000000..1f7b6172 --- /dev/null +++ b/src/Services/Telephony/Voximplant/Line/Result/VoximplantLineIdItemResult.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\Line\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read non-empty-string $LINE_ID + */ +class VoximplantLineIdItemResult extends AbstractItem +{ +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/Line/Result/VoximplantLineIdResult.php b/src/Services/Telephony/Voximplant/Line/Result/VoximplantLineIdResult.php new file mode 100644 index 00000000..517e334c --- /dev/null +++ b/src/Services/Telephony/Voximplant/Line/Result/VoximplantLineIdResult.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\Line\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; +use Bitrix24\SDK\Services\Telephony\ExternalCall\Result\ExternalCallFinishedItemResult; +use Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result\SipLineStatusItemResult; + +class VoximplantLineIdResult extends AbstractResult +{ + public function getLineId(): VoximplantLineIdItemResult + { + return new VoximplantLineIdItemResult(['LINE_ID' => $this->getCoreResponse()->getResponseData()->getResult()[0]]); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/Line/Result/VoximplantLineItemResult.php b/src/Services/Telephony/Voximplant/Line/Result/VoximplantLineItemResult.php new file mode 100644 index 00000000..acd04a4d --- /dev/null +++ b/src/Services/Telephony/Voximplant/Line/Result/VoximplantLineItemResult.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\Line\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read non-empty-string $LINE_ID + * @property-read non-empty-string $NUMBER + */ +class VoximplantLineItemResult extends AbstractItem +{ +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/Line/Result/VoximplantLinesResult.php b/src/Services/Telephony/Voximplant/Line/Result/VoximplantLinesResult.php new file mode 100644 index 00000000..3069b32e --- /dev/null +++ b/src/Services/Telephony/Voximplant/Line/Result/VoximplantLinesResult.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\Line\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; +use Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result\SipLineItemResult; + +class VoximplantLinesResult extends AbstractResult +{ + /** + * @return VoximplantLineItemResult[] + * @throws BaseException + */ + public function getLines(): array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $lineId => $line) { + $res[] = new VoximplantLineItemResult([ + 'LINE_ID' => $lineId, + 'NUMBER' => $line + ]); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/Line/Service/Batch.php b/src/Services/Telephony/Voximplant/Line/Service/Batch.php new file mode 100644 index 00000000..ddc7759b --- /dev/null +++ b/src/Services/Telephony/Voximplant/Line/Service/Batch.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\Line\Service; + +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +use Psr\Log\LoggerInterface; + +readonly class Batch +{ + public function __construct( + protected BatchOperationsInterface $batch, + protected LoggerInterface $log) + { + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/Line/Service/Line.php b/src/Services/Telephony/Voximplant/Line/Service/Line.php new file mode 100644 index 00000000..e4e9ee20 --- /dev/null +++ b/src/Services/Telephony/Voximplant/Line/Service/Line.php @@ -0,0 +1,109 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\Line\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Telephony\Voximplant\Line\Result\VoximplantLineIdResult; +use Bitrix24\SDK\Services\Telephony\Voximplant\Line\Result\VoximplantLinesResult; +use Psr\Log\LoggerInterface; +#[ApiServiceMetadata(new Scope(['telephony']))] +class Line extends AbstractService +{ + public function __construct( + readonly public Batch $batch, + CoreInterface $core, + LoggerInterface $logger + ) + { + parent::__construct($core, $logger); + } + + /** + * Sets the selected SIP line as an outgoing line by default. + * + * This method is available to the user with granted access permissions for Manage numbers - Edit - Any. + * @link https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_line_outgoing_sip_set.php + */ + #[ApiEndpointMetadata( + 'voximplant.line.outgoing.sip.set', + 'https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_line_outgoing_sip_set.php', + 'Sets the selected SIP line as an outgoing line by default.' + )] + public function outgoingSipSet(int $sipLineId): UserInterfaceDialogCallResult + { + return new UserInterfaceDialogCallResult($this->core->call('voximplant.line.outgoing.sip.set', [ + 'CONFIG_ID' => $sipLineId + ])); + } + + /** + * Returns list of all of the available outgoing lines. + * + * @link https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_line_get.php + */ + #[ApiEndpointMetadata( + 'voximplant.line.get', + 'https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_line_get.php', + 'Returns list of all of the available outgoing lines.' + )] + public function get(): VoximplantLinesResult + { + return new VoximplantLinesResult($this->core->call('voximplant.line.get')); + } + + /** + * Returns the currently selected line as an outgoing line by default. + * + * This method is available to the user with granted access permissions for Manage numbers - Edit - Any. + * + * @link https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_line_outgoing_get.php + */ + #[ApiEndpointMetadata( + 'voximplant.line.outgoing.get', + 'https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_line_outgoing_get.php', + 'Returns the currently selected line as an outgoing line by default.' + )] + public function outgoingGet(): VoximplantLineIdResult + { + return new VoximplantLineIdResult($this->core->call('voximplant.line.outgoing.get')); + } + + /** + * Sets the selected line as an outgoing line by default. + * + * This method is available to the user with granted access permissions for Manage numbers - Edit - Any. + * @link https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_line_outgoing_set.php + * @param string $lineId Line identifier obtained from the method voximplant.line.get or voximplant.line.outgoing.get. + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'voximplant.line.outgoing.set', + 'https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_line_outgoing_set.php', + 'Sets the selected line as an outgoing line by default.' + )] + public function outgoingSet(string $lineId): UserInterfaceDialogCallResult + { + return new UserInterfaceDialogCallResult($this->core->call('voximplant.line.outgoing.set', [ + 'LINE_ID' => $lineId + ])); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/Sip/Result/SipConnectorStatusItemResult.php b/src/Services/Telephony/Voximplant/Sip/Result/SipConnectorStatusItemResult.php new file mode 100644 index 00000000..3a8c330a --- /dev/null +++ b/src/Services/Telephony/Voximplant/Sip/Result/SipConnectorStatusItemResult.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; +use Carbon\CarbonImmutable; + +/** + * @property-read int $FREE_MINUTES Number of free minutes for integration setup and testing. + * @property-read bool $PAID Indicates whether the connector is paid for or not. + * @property-read ?CarbonImmutable $PAID_DATE_END Indicates the date through which the connector is paid (if payment was made). + */ +class SipConnectorStatusItemResult extends AbstractItem +{ + public function __get($offset) + { + switch ($offset) { + case 'FREE_MINUTES': + return $this->data[$offset]; + case 'PAID': + return (bool)$this->data[$offset]; + case 'PAID_DATE_END': + if ($this->data[$offset] !== '') { + return CarbonImmutable::createFromFormat(DATE_ATOM, $this->data[$offset]); + } + + return null; + default: + return $this->data[$offset] ?? null; + } + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/Sip/Result/SipConnectorStatusResult.php b/src/Services/Telephony/Voximplant/Sip/Result/SipConnectorStatusResult.php new file mode 100644 index 00000000..1df8ce4f --- /dev/null +++ b/src/Services/Telephony/Voximplant/Sip/Result/SipConnectorStatusResult.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class SipConnectorStatusResult extends AbstractResult +{ + public function getStatus(): SipConnectorStatusItemResult + { + return new SipConnectorStatusItemResult($this->getCoreResponse()->getResponseData()->getResult()); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/Sip/Result/SipLineAddedResult.php b/src/Services/Telephony/Voximplant/Sip/Result/SipLineAddedResult.php new file mode 100644 index 00000000..3df894d0 --- /dev/null +++ b/src/Services/Telephony/Voximplant/Sip/Result/SipLineAddedResult.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; +use Bitrix24\SDK\Services\Telephony\ExternalCall\Result\ExternalCallFinishedItemResult; + +class SipLineAddedResult extends AbstractResult +{ + public function getLine(): SipLineItemResult + { + return new SipLineItemResult($this->getCoreResponse()->getResponseData()->getResult()); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/Sip/Result/SipLineItemResult.php b/src/Services/Telephony/Voximplant/Sip/Result/SipLineItemResult.php new file mode 100644 index 00000000..3ee86ada --- /dev/null +++ b/src/Services/Telephony/Voximplant/Sip/Result/SipLineItemResult.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; +use Bitrix24\SDK\Services\Telephony\Common\CrmEntity; +use Bitrix24\SDK\Services\Telephony\Common\CrmEntityType; +use Bitrix24\SDK\Services\Telephony\Common\PbxType; +use Money\Currency; +use Money\Money; + +/** + * @property-read int $ID + * @property-read PbxType $TYPE PBX type + * @property-read int $CONFIG_ID SIP line setup identifier. + * @property-read int $REG_ID SIP registration identifier (for cloud hosted PBX only). + * @property-read non-empty-string $SERVER SIP registration server address for cloud hosted PBX or server address for office PBX. + * @property-read non-empty-string $LOGIN Server login. + * @property-read non-empty-string $PASSWORD Server password. + * @property-read mixed $AUTH_USER + * @property-read mixed $OUTBOUND_PROXY + * @property-read mixed $DETECT_LINE_NUMBER + * @property-read string $LINE_DETECT_HEADER_ORDER + * @property-read mixed $REGISTRATION_STATUS_CODE + * @property-read mixed $REGISTRATION_ERROR_MESSAGE + * @property-read non-empty-string $TITLE + */ +class SipLineItemResult extends AbstractItem +{ + public function __get($offset) + { + return match ($offset) { + 'ID', 'REG_ID', 'CONFIG_ID' => (int)$this->data[$offset], + 'TYPE' => PbxType::from($this->data[$offset]), + default => $this->data[$offset] ?? null, + }; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/Sip/Result/SipLineStatusItemResult.php b/src/Services/Telephony/Voximplant/Sip/Result/SipLineStatusItemResult.php new file mode 100644 index 00000000..3480d135 --- /dev/null +++ b/src/Services/Telephony/Voximplant/Sip/Result/SipLineStatusItemResult.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; +use Bitrix24\SDK\Services\Telephony\Common\CrmEntity; +use Bitrix24\SDK\Services\Telephony\Common\CrmEntityType; +use Bitrix24\SDK\Services\Telephony\Common\PbxType; +use Bitrix24\SDK\Services\Telephony\Common\SipRegistrationStatus; +use Carbon\CarbonImmutable; +use Money\Currency; +use Money\Money; + +/** + * @property-read int $REG_ID SIP registration identifier (for cloud hosted PBX only). + * @property-read CarbonImmutable $LAST_UPDATED Date of the last change of SIP registration. + * @property-read non-empty-string|null $ERROR_MESSAGE Error code textual description. + * @property-read non-empty-string|null $STATUS_CODE Error numeric code. + * @property-read SipRegistrationStatus $STATUS_RESULT SIP registration status + */ +class SipLineStatusItemResult extends AbstractItem +{ + public function __get($offset) + { + return match ($offset) { + 'REG_ID' => (int)$this->data[$offset], + 'LAST_UPDATED' => CarbonImmutable::createFromTimeString($this->data[$offset]), + 'STATUS_RESULT' => SipRegistrationStatus::from($this->data[$offset]), + default => $this->data[$offset] ?? null, + }; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/Sip/Result/SipLineStatusResult.php b/src/Services/Telephony/Voximplant/Sip/Result/SipLineStatusResult.php new file mode 100644 index 00000000..94078b3d --- /dev/null +++ b/src/Services/Telephony/Voximplant/Sip/Result/SipLineStatusResult.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; +use Bitrix24\SDK\Services\Telephony\ExternalCall\Result\ExternalCallFinishedItemResult; + +class SipLineStatusResult extends AbstractResult +{ + public function getStatus(): SipLineStatusItemResult + { + return new SipLineStatusItemResult($this->getCoreResponse()->getResponseData()->getResult()); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/Sip/Result/SipLinesResult.php b/src/Services/Telephony/Voximplant/Sip/Result/SipLinesResult.php new file mode 100644 index 00000000..1abba0d0 --- /dev/null +++ b/src/Services/Telephony/Voximplant/Sip/Result/SipLinesResult.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class SipLinesResult extends AbstractResult +{ + /** + * @return SipLineItemResult[] + * @throws BaseException + */ + public function getLines(): array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $line) { + $res[] = new SipLineItemResult($line); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/Sip/Service/Batch.php b/src/Services/Telephony/Voximplant/Sip/Service/Batch.php new file mode 100644 index 00000000..860cb617 --- /dev/null +++ b/src/Services/Telephony/Voximplant/Sip/Service/Batch.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Service; + +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +use Psr\Log\LoggerInterface; + +readonly class Batch +{ + public function __construct( + protected BatchOperationsInterface $batch, + protected LoggerInterface $log) + { + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/Sip/Service/Sip.php b/src/Services/Telephony/Voximplant/Sip/Service/Sip.php new file mode 100644 index 00000000..600bb347 --- /dev/null +++ b/src/Services/Telephony/Voximplant/Sip/Service/Sip.php @@ -0,0 +1,201 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\DeletedItemResult; +use Bitrix24\SDK\Core\Result\UpdatedItemResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Telephony\Common\PbxType; +use Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result\SipConnectorStatusResult; +use Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result\SipLineAddedResult; +use Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result\SipLinesResult; +use Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result\SipLineStatusResult; +use Psr\Log\LoggerInterface; +#[ApiServiceMetadata(new Scope(['telephony']))] +class Sip extends AbstractService +{ + public function __construct( + readonly public Batch $batch, + CoreInterface $core, + LoggerInterface $logger + ) + { + parent::__construct($core, $logger); + } + + /** + * Returns the current status of the SIP Connector. + * + * This method is available to the user with granted access permissions for Manage numbers - Edit - Any. + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_sip_connector_status.php + */ + #[ApiEndpointMetadata( + 'voximplant.sip.connector.status', + 'https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_sip_connector_status.php', + 'Returns the current status of the SIP Connector.' + )] + public function getConnectorStatus(): SipConnectorStatusResult + { + return new SipConnectorStatusResult($this->core->call('voximplant.sip.connector.status')); + } + + /** + * Creates a new SIP line linked to the application. Once created, this line becomes an outbound line by default. + * + * This method is available to the user with granted access permissions for Manage numbers - Edit - Any. + * + * @link https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_sip_add.php + */ + #[ApiEndpointMetadata( + 'voximplant.sip.add', + 'https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_sip_add.php', + 'Сreates a new SIP line linked to the application. Once created, this line becomes an outbound line by default.' + )] + public function add( + PbxType $pbxType, + string $title, + string $serverUrl, + string $login, + string $password + ): SipLineAddedResult + { + return new SipLineAddedResult($this->core->call('voximplant.sip.add', [ + 'TYPE' => $pbxType->value, + 'TITLE' => $title, + 'SERVER' => $serverUrl, + 'LOGIN' => $login, + 'PASSWORD' => $password + ])); + } + + /** + * Deletes the current SIP line (created by the application). + * + * This method is available to the user with granted access permissions for Manage numbers - Edit - Any. + * @param int $sipConfigId SIP line setup identifier. + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_sip_delete.php + */ + #[ApiEndpointMetadata( + 'voximplant.sip.delete', + 'https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_sip_delete.php', + 'Deletes the current SIP line (created by the application).' + )] + public function delete(int $sipConfigId): DeletedItemResult + { + return new DeletedItemResult($this->core->call('voximplant.sip.delete', [ + 'CONFIG_ID' => $sipConfigId + ])); + } + + /** + * Returns the list of all SIP lines created by the application. It is a list method. + * + * This method is available to the user with granted access permissions for Manage numbers - Edit - Any. + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_sip_get.php + */ + #[ApiEndpointMetadata( + 'voximplant.sip.get', + 'https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_sip_get.php', + 'Returns the list of all SIP lines created by the application. It is a list method.' + )] + public function get(): SipLinesResult + { + return new SipLinesResult($this->core->call('voximplant.sip.get')); + } + + /** + * Returns the current status of the SIP registration (for cloud hosted PBX only). + * + * This method is available to the user with granted access permissions for Manage numbers - Edit - Any. + * + * @link https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_sip_status.php + * @param int $sipRegistrationId SIP registration identifier. + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'voximplant.sip.status', + 'https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_sip_status.php', + 'Returns the current status of the SIP registration (for cloud hosted PBX only).' + )] + public function status(int $sipRegistrationId): SipLineStatusResult + { + return new SipLineStatusResult($this->core->call('voximplant.sip.status', [ + 'REG_ID' => $sipRegistrationId + ])); + } + + /** + * Updates the existing SIP line (created by the application). + * + * This method is available to the user with granted access permissions for Manage numbers - Edit - Any. + * + * @link https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_sip_update.php + * @throws InvalidArgumentException + */ + #[ApiEndpointMetadata( + 'voximplant.sip.update', + 'https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_sip_update.php', + 'Updates the existing SIP line (created by the application).' + )] + public function update(int $sipConfigId, + PbxType $pbxType, + ?string $title = null, + ?string $serverUrl = null, + ?string $login = null, + ?string $password = null): UpdatedItemResult + { + $fieldsForUpdate = []; + if ($title !== null) { + $fieldsForUpdate['TITLE'] = $title; + } + + if ($serverUrl !== null) { + $fieldsForUpdate['SERVER'] = $serverUrl; + } + + if ($login !== null) { + $fieldsForUpdate['LOGIN'] = $login; + } + + if ($password !== null) { + $fieldsForUpdate['PASSWORD'] = $password; + } + + if ($fieldsForUpdate === []) { + throw new InvalidArgumentException('you must set minimum one field: title, server, login, password'); + } + + return new UpdatedItemResult($this->core->call('voximplant.sip.update', + array_merge([ + 'CONFIG_ID' => $sipConfigId, + 'TYPE' => $pbxType->name + ], + $fieldsForUpdate) + )); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/TTS/Voices/Result/VoximplantVoiceItemResult.php b/src/Services/Telephony/Voximplant/TTS/Voices/Result/VoximplantVoiceItemResult.php new file mode 100644 index 00000000..acd636d3 --- /dev/null +++ b/src/Services/Telephony/Voximplant/TTS/Voices/Result/VoximplantVoiceItemResult.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\TTS\Voices\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read non-empty-string $CODE + * @property-read non-empty-string $NAME + */ +class VoximplantVoiceItemResult extends AbstractItem +{ +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/TTS/Voices/Result/VoximplantVoicesResult.php b/src/Services/Telephony/Voximplant/TTS/Voices/Result/VoximplantVoicesResult.php new file mode 100644 index 00000000..b0c7beed --- /dev/null +++ b/src/Services/Telephony/Voximplant/TTS/Voices/Result/VoximplantVoicesResult.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\TTS\Voices\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class VoximplantVoicesResult extends AbstractResult +{ + /** + * @return VoximplantVoiceItemResult[] + * @throws BaseException + */ + public function getVoices(): array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $code => $voice) { + $res[] = new VoximplantVoiceItemResult([ + 'CODE' => $code, + 'NAME' => $voice + ]); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/TTS/Voices/Service/Batch.php b/src/Services/Telephony/Voximplant/TTS/Voices/Service/Batch.php new file mode 100644 index 00000000..b08b5f89 --- /dev/null +++ b/src/Services/Telephony/Voximplant/TTS/Voices/Service/Batch.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\TTS\Voices\Service; + +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +use Psr\Log\LoggerInterface; + +readonly class Batch +{ + public function __construct( + protected BatchOperationsInterface $batch, + protected LoggerInterface $log) + { + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/TTS/Voices/Service/Voices.php b/src/Services/Telephony/Voximplant/TTS/Voices/Service/Voices.php new file mode 100644 index 00000000..6428f39a --- /dev/null +++ b/src/Services/Telephony/Voximplant/TTS/Voices/Service/Voices.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\TTS\Voices\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\AbstractService; + +use Bitrix24\SDK\Services\Telephony\Voximplant\TTS\Voices\Result\VoximplantVoicesResult; +use Psr\Log\LoggerInterface; + +#[ApiServiceMetadata(new Scope(['telephony']))] +class Voices extends AbstractService +{ + public function __construct( + readonly public Batch $batch, + CoreInterface $core, + LoggerInterface $logger + ) + { + parent::__construct($core, $logger); + } + + /** + * Returns an array of available voices for generation of speech in the format of voice ID => voice name. + * + * This method does not have limitation of access permissions . + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_tts_voices.get.php + */ + #[ApiEndpointMetadata( + 'voximplant.tts.voices.get', + 'https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_tts_voices.get.php', + 'Returns an array of available voices for generation of speech in the format of voice ID => voice name.' + )] + public function get(): VoximplantVoicesResult + { + return new VoximplantVoicesResult($this->core->call('voximplant.tts.voices.get')); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/Url/Result/VoximplantPagesItemResult.php b/src/Services/Telephony/Voximplant/Url/Result/VoximplantPagesItemResult.php new file mode 100644 index 00000000..54e75210 --- /dev/null +++ b/src/Services/Telephony/Voximplant/Url/Result/VoximplantPagesItemResult.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\Url\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read non-empty-string $detail_statistics + * @property-read non-empty-string $buy_connector + * @property-read non-empty-string $edit_config + * @property-read non-empty-string $lines + */ +class VoximplantPagesItemResult extends AbstractItem +{ +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/Url/Result/VoximplantPagesResult.php b/src/Services/Telephony/Voximplant/Url/Result/VoximplantPagesResult.php new file mode 100644 index 00000000..48ba7581 --- /dev/null +++ b/src/Services/Telephony/Voximplant/Url/Result/VoximplantPagesResult.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\Url\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class VoximplantPagesResult extends AbstractResult +{ + public function getPages(): VoximplantPagesItemResult + { + return new VoximplantPagesItemResult($this->getCoreResponse()->getResponseData()->getResult()); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/Url/Service/Batch.php b/src/Services/Telephony/Voximplant/Url/Service/Batch.php new file mode 100644 index 00000000..362fcd67 --- /dev/null +++ b/src/Services/Telephony/Voximplant/Url/Service/Batch.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\Url\Service; + +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +use Psr\Log\LoggerInterface; + +readonly class Batch +{ + public function __construct( + protected BatchOperationsInterface $batch, + protected LoggerInterface $log) + { + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/Url/Service/Url.php b/src/Services/Telephony/Voximplant/Url/Service/Url.php new file mode 100644 index 00000000..0e43112a --- /dev/null +++ b/src/Services/Telephony/Voximplant/Url/Service/Url.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\Url\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Telephony\Voximplant\Url\Result\VoximplantPagesResult; +use Psr\Log\LoggerInterface; +#[ApiServiceMetadata(new Scope(['telephony']))] +class Url extends AbstractService +{ + public function __construct( + readonly public Batch $batch, + CoreInterface $core, + LoggerInterface $logger + ) + { + parent::__construct($core, $logger); + } + + /** + * Returns a set of links for browsing telephony scope pages. + * + * This method does not have limitations of access permissions. + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_url_get.php + */ + #[ApiEndpointMetadata( + 'voximplant.url.get', + 'https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_url_get.php', + 'Returns a set of links for browsing telephony scope pages.' + )] + public function get(): VoximplantPagesResult + { + return new VoximplantPagesResult($this->core->call('voximplant.url.get')); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/User/Result/VoximplantUserSettingsItemResult.php b/src/Services/Telephony/Voximplant/User/Result/VoximplantUserSettingsItemResult.php new file mode 100644 index 00000000..e55eece5 --- /dev/null +++ b/src/Services/Telephony/Voximplant/User/Result/VoximplantUserSettingsItemResult.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\User\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * @property-read int $ID User ID + * @property-read non-empty-string|null $DEFAULT_LINE + * @property-read bool $PHONE_ENABLED + * @property-read non-empty-string $SIP_SERVER + * @property-read non-empty-string $SIP_LOGIN + * @property-read non-empty-string|null $SIP_PASSWORD + * @property-read non-empty-string $INNER_NUMBER + */ +class VoximplantUserSettingsItemResult extends AbstractItem +{ + public function __get($offset) + { + return match ($offset) { + 'ID' => (int)$this->data[$offset], + 'PHONE_ENABLED' => (bool)$this->data[$offset], + default => $this->data[$offset] ?? null, + }; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/User/Result/VoximplantUserSettingsResult.php b/src/Services/Telephony/Voximplant/User/Result/VoximplantUserSettingsResult.php new file mode 100644 index 00000000..e992d305 --- /dev/null +++ b/src/Services/Telephony/Voximplant/User/Result/VoximplantUserSettingsResult.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\User\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class VoximplantUserSettingsResult extends AbstractResult +{ + /** + * @return VoximplantUserSettingsItemResult[] + * @throws BaseException + */ + public function getUsers(): array + { + $items = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $user) { + $items[] = new VoximplantUserSettingsItemResult($user); + } + + return $items; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/User/Service/Batch.php b/src/Services/Telephony/Voximplant/User/Service/Batch.php new file mode 100644 index 00000000..90593a2c --- /dev/null +++ b/src/Services/Telephony/Voximplant/User/Service/Batch.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\User\Service; + +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +use Psr\Log\LoggerInterface; + +readonly class Batch +{ + public function __construct( + protected BatchOperationsInterface $batch, + protected LoggerInterface $log) + { + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/User/Service/User.php b/src/Services/Telephony/Voximplant/User/Service/User.php new file mode 100644 index 00000000..cc59ccd8 --- /dev/null +++ b/src/Services/Telephony/Voximplant/User/Service/User.php @@ -0,0 +1,103 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant\User\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Telephony\Voximplant\User\Result\VoximplantUserSettingsResult; +use Psr\Log\LoggerInterface; +#[ApiServiceMetadata(new Scope(['telephony']))] +class User extends AbstractService +{ + public function __construct( + readonly public Batch $batch, + CoreInterface $core, + LoggerInterface $logger + ) + { + parent::__construct($core, $logger); + } + + /** + * This method disables an indicator of SIP-phone availability. Method checks the availability of the access permissions to modify users. + * + * This method is accessible to the user with access permissionsgranted for User Settings - Action. + * + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_user_deactivatePhone.php + */ + #[ApiEndpointMetadata( + 'voximplant.user.deactivatePhone', + 'https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_user_deactivatePhone.php', + 'This method disables an indicator of SIP-phone availability. Method checks the availability of the access permissions to modify users.' + )] + public function deactivatePhone(int $userId): UserInterfaceDialogCallResult + { + return new UserInterfaceDialogCallResult($this->core->call('voximplant.user.deactivatePhone', [ + 'USER_ID' => $userId + ])); + } + + /** + * This method raises the event of SIP-phone availability for an employee. Method checks the availability of the access permissions to modify users. + * + * This method is accessible to the user with access permissionsgranted for User Settings - Action. + * + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_user_activatePhone.php + */ + #[ApiEndpointMetadata( + 'voximplant.user.activatePhone', + 'https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_user_activatePhone.php', + 'This method raises the event of SIP-phone availability for an employee. Method checks the availability of the access permissions to modify users.' + )] + public function activatePhone(int $userId): UserInterfaceDialogCallResult + { + return new UserInterfaceDialogCallResult($this->core->call('voximplant.user.activatePhone', [ + 'USER_ID' => $userId + ])); + } + + /** + * This method returns user settings. + * + * Method checks the availability of the access permission rights to modify the user and requests the confirmation of administrator prior to completion. + * This method is available to the user with granted access permissions for Manage numbers - Edit - Any. + * + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_user_get.php + */ + #[ApiEndpointMetadata( + 'voximplant.user.get', + 'https://training.bitrix24.com/rest_help/scope_telephony/voximplant/voximplant_user_get.php', + 'This method returns user settings.' + )] + public function get(array $userIds): VoximplantUserSettingsResult + { + return new VoximplantUserSettingsResult($this->core->call('voximplant.user.get', + [ + 'USER_ID' => $userIds + ] + )); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/VoximplantServiceBuilder.php b/src/Services/Telephony/Voximplant/VoximplantServiceBuilder.php new file mode 100644 index 00000000..1bb65ad9 --- /dev/null +++ b/src/Services/Telephony/Voximplant/VoximplantServiceBuilder.php @@ -0,0 +1,100 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Telephony\Voximplant; + +use Bitrix24\SDK\Infrastructure\Filesystem\Base64Encoder; +use Bitrix24\SDK\Services\AbstractServiceBuilder; +use Bitrix24\SDK\Services\Telephony; +use Symfony\Component\Filesystem\Filesystem; + +class VoximplantServiceBuilder extends AbstractServiceBuilder +{ + public function sip(): Telephony\Voximplant\Sip\Service\Sip + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Telephony\Voximplant\Sip\Service\Sip( + new Telephony\Voximplant\Sip\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + + public function user(): Telephony\Voximplant\User\Service\User + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Telephony\Voximplant\User\Service\User( + new Telephony\Voximplant\User\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + + public function infoCall(): Telephony\Voximplant\InfoCall\Service\InfoCall + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Telephony\Voximplant\InfoCall\Service\InfoCall( + new Telephony\Voximplant\InfoCall\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + + public function ttsVoices(): Telephony\Voximplant\TTS\Voices\Service\Voices + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Telephony\Voximplant\TTS\Voices\Service\Voices( + new Telephony\Voximplant\TTS\Voices\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + + public function line(): Telephony\Voximplant\Line\Service\Line + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Telephony\Voximplant\Line\Service\Line( + new Telephony\Voximplant\Line\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + + public function url(): Telephony\Voximplant\Url\Service\Url + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Telephony\Voximplant\Url\Service\Url( + new Telephony\Voximplant\Url\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } +} \ No newline at end of file diff --git a/src/Services/User/Result/UserItemResult.php b/src/Services/User/Result/UserItemResult.php new file mode 100644 index 00000000..bd4061c9 --- /dev/null +++ b/src/Services/User/Result/UserItemResult.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\User\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; +use Carbon\CarbonImmutable; + +/** + * @property-read int $ID + * @property-read string $XML_ID + * @property-read bool $ACTIVE + * @property-read string $NAME + * @property-read string $LAST_NAME + * @property-read string $SECOND_NAME + * @property-read string $TITLE + * @property-read string $EMAIL + * @property-read CarbonImmutable $LAST_LOGIN + * @property-read CarbonImmutable $DATE_REGISTER + * @property-read string $TIME_ZONE + * @property-read bool $IS_ONLINE + * @property-read int $TIME_ZONE_OFFSET + * @property-read array $TIMESTAMP_X + * @property-read array $LAST_ACTIVITY_DATE + * @property-read string $PERSONAL_GENDER + * @property-read string $PERSONAL_WWW + * @property-read CarbonImmutable $PERSONAL_BIRTHDAY + * @property-read string $PERSONAL_PHOTO + * @property-read string $PERSONAL_MOBILE + * @property-read string $PERSONAL_CITY + * @property-read string $WORK_PHONE + * @property-read CarbonImmutable $UF_EMPLOYMENT_DATE + * @property-read string $UF_TIMEMAN + * @property-read array $UF_DEPARTMENT + * @property-read string $UF_PHONE_INNER + * @property-read string $USER_TYPE + */ +class UserItemResult extends AbstractItem +{ + public function __get($offset) + { + switch ($offset) { + case 'ID': + case 'TIME_ZONE_OFFSET': + return (int)$this->data[$offset]; + case 'LAST_LOGIN': + case 'DATE_REGISTER': + case 'UF_EMPLOYMENT_DATE': + case 'PERSONAL_BIRTHDAY': + if ($this->data[$offset] !== '') { + return CarbonImmutable::createFromFormat(DATE_ATOM, $this->data[$offset]); + } + + break; + case 'IS_ONLINE': + return $this->data[$offset] === 'Y'; + } + + return $this->data[$offset] ?? null; + } +} \ No newline at end of file diff --git a/src/Services/User/Result/UserResult.php b/src/Services/User/Result/UserResult.php new file mode 100644 index 00000000..928a6697 --- /dev/null +++ b/src/Services/User/Result/UserResult.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\User\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class UserResult extends AbstractResult +{ + public function user(): UserItemResult + { + return new UserItemResult($this->getCoreResponse()->getResponseData()->getResult()); + } +} \ No newline at end of file diff --git a/src/Services/User/Result/UsersResult.php b/src/Services/User/Result/UsersResult.php new file mode 100644 index 00000000..94881973 --- /dev/null +++ b/src/Services/User/Result/UsersResult.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\User\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; +use Bitrix24\SDK\Services\CRM\Contact\Result\ContactItemResult; + +class UsersResult extends AbstractResult +{ + /** + * @return UserItemResult[] + * @throws BaseException + */ + public function getUsers(): array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { + $res[] = new UserItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/User/Service/User.php b/src/Services/User/Service/User.php new file mode 100644 index 00000000..13c55978 --- /dev/null +++ b/src/Services/User/Service/User.php @@ -0,0 +1,155 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\User\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\AddedItemResult; +use Bitrix24\SDK\Core\Result\FieldsResult; +use Bitrix24\SDK\Core\Result\UpdatedItemResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\User\Result\UserResult; +use Bitrix24\SDK\Services\User\Result\UsersResult; + +#[ApiServiceMetadata(new Scope(['user']))] +class User extends AbstractService +{ + /** + * Get user entity fields + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/users/user_fields.php + */ + #[ApiEndpointMetadata( + 'user.fields', + 'https://training.bitrix24.com/rest_help/users/user_fields.php', + 'Get user entity fields' + )] + public function fields(): FieldsResult + { + return new FieldsResult($this->core->call('user.fields')); + } + + /** + * Get current user + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/users/user_current.php + */ + #[ApiEndpointMetadata( + 'user.current', + 'https://training.bitrix24.com/rest_help/users/user_current.php', + 'Get current user' + )] + public function current(): UserResult + { + return new UserResult($this->core->call('user.current')); + } + + /** + * Invites a user. Available only for users with invitation permissions, usually an administrator. Sends a standard account invitation to the user on success. + * + * @param array $fields = ['ID','XML_ID','ACTIVE','NAME','LAST_NAME','SECOND_NAME','TITLE','EMAIL','PERSONAL_PHONE','WORK_PHONE','WORK_POSITION','WORK_COMPANY','IS_ONLINE','TIME_ZONE','TIMESTAMP_X','TIME_ZONE_OFFSET','DATE_REGISTER','LAST_ACTIVITY_DATE','PERSONAL_PROFESSION','PERSONAL_GENDER','PERSONAL_BIRTHDAY','PERSONAL_PHOTO','PERSONAL_FAX','PERSONAL_MOBILE','PERSONAL_PAGER','PERSONAL_STREET','PERSONAL_MAILBOX','PERSONAL_CITY','PERSONAL_STATE','PERSONAL_ZIP','PERSONAL_COUNTRY','PERSONAL_NOTES','WORK_DEPARTMENT','WORK_WWW','WORK_FAX','WORK_PAGER','WORK_STREET','WORK_MAILBOX','WORK_CITY','WORK_STATE','WORK_ZIP','WORK_COUNTRY','WORK_PROFILE','WORK_LOGO','WORK_NOTES','UF_DEPARTMENT','UF_DISTRICT','UF_SKYPE','UF_SKYPE_LINK','UF_ZOOM','UF_TWITTER','UF_FACEBOOK','UF_LINKEDIN','UF_XING','UF_WEB_SITES','UF_PHONE_INNER','UF_EMPLOYMENT_DATE','UF_TIMEMAN','UF_SKILLS','UF_INTERESTS','USER_TYPE'] + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/users/user_add.php + */ + #[ApiEndpointMetadata( + 'user.add', + 'https://training.bitrix24.com/rest_help/users/user_add.php', + 'Invites a user. Available only for users with invitation permissions, usually an administrator. Sends a standard account invitation to the user on success.' + )] + public function add(array $fields, string $messageText = ''): AddedItemResult + { + if (!array_key_exists('EXTRANET', $fields)) { + throw new InvalidArgumentException('field EXTRANET is required'); + } + + return new AddedItemResult($this->core->call( + 'user.add', + array_merge( + $fields, + [ + 'MESSAGE_TEXT' => $messageText + ] + ) + )); + } + + /** + * @param array $filter = ['ID','XML_ID','ACTIVE','NAME','LAST_NAME','SECOND_NAME','TITLE','EMAIL','PERSONAL_PHONE','WORK_PHONE','WORK_POSITION','WORK_COMPANY','IS_ONLINE','TIME_ZONE','TIMESTAMP_X','TIME_ZONE_OFFSET','DATE_REGISTER','LAST_ACTIVITY_DATE','PERSONAL_PROFESSION','PERSONAL_GENDER','PERSONAL_BIRTHDAY','PERSONAL_PHOTO','PERSONAL_FAX','PERSONAL_MOBILE','PERSONAL_PAGER','PERSONAL_STREET','PERSONAL_MAILBOX','PERSONAL_CITY','PERSONAL_STATE','PERSONAL_ZIP','PERSONAL_COUNTRY','PERSONAL_NOTES','WORK_DEPARTMENT','WORK_WWW','WORK_FAX','WORK_PAGER','WORK_STREET','WORK_MAILBOX','WORK_CITY','WORK_STATE','WORK_ZIP','WORK_COUNTRY','WORK_PROFILE','WORK_LOGO','WORK_NOTES','UF_DEPARTMENT','UF_DISTRICT','UF_SKYPE','UF_SKYPE_LINK','UF_ZOOM','UF_TWITTER','UF_FACEBOOK','UF_LINKEDIN','UF_XING','UF_WEB_SITES','UF_PHONE_INNER','UF_EMPLOYMENT_DATE','UF_TIMEMAN','UF_SKILLS','UF_INTERESTS','USER_TYPE'] + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'user.get', + 'https://training.bitrix24.com/rest_help/users/user_get.php', + 'Get user by id' + )] + public function get(array $order, array $filter, bool $isAdminMode = false): UsersResult + { + if ($order === []) { + $order = ['ID' => 'ASC']; + } + + return new UsersResult($this->core->call('user.get', [ + 'sort' => array_keys($order)[0], + 'order' => array_values($order)[0], + 'filter' => $filter, + 'ADMIN_MODE' => $isAdminMode ? 'true' : 'false' + ])); + } + + /** + * Updates user information. Available only for users with invitation permissions. + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/users/user_update.php + */ + #[ApiEndpointMetadata( + 'user.update', + 'https://training.bitrix24.com/rest_help/users/user_get.php', + 'Updates user information. Available only for users with invitation permissions.' + )] + public function update(int $userId, array $fields): UpdatedItemResult + { + return new UpdatedItemResult($this->core->call('user.update', array_merge( + $fields, + [ + 'ID' => $userId + ] + ))); + } + + /** + * This method is used to retrieve list of users with expedited personal data search (name, last name, middle name, name of department, position). Works in two modes: Quick mode, via Fulltext Index and slower mode via right LIKE (support is determined automatically). + * + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/users/user_search.php + */ + #[ApiEndpointMetadata( + 'user.search', + 'https://training.bitrix24.com/rest_help/users/user_search.php', + 'This method is used to retrieve list of users with expedited personal data search.' + )] + public function search(array $filterFields): UsersResult + { + return new UsersResult($this->core->call('user.search', $filterFields)); + } +} \ No newline at end of file diff --git a/src/Services/User/UserServiceBuilder.php b/src/Services/User/UserServiceBuilder.php new file mode 100644 index 00000000..aee42ca8 --- /dev/null +++ b/src/Services/User/UserServiceBuilder.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\User; + +use Bitrix24\SDK\Services\AbstractServiceBuilder; +use Bitrix24\SDK\Services\User\Service\User; + +class UserServiceBuilder extends AbstractServiceBuilder +{ + public function user(): User + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new User($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..cc802d3c --- /dev/null +++ b/src/Services/UserConsent/Result/UserConsentAgreementItemResult.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\UserConsent\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * Class UserConsentAgreementItemResult + * + * @property-read int $ID + * @property-read string $NAME + * @property-read string $LANGUAGE_ID + * @property-read boolean $ACTIVE + */ +class UserConsentAgreementItemResult extends AbstractItem +{ + /** + * @param int|string $offset + * + * @return bool|int|mixed|null + */ + public function __get($offset) + { + switch ($offset) { + case 'ID': + if ($this->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..2763d672 --- /dev/null +++ b/src/Services/UserConsent/Result/UserConsentAgreementResult.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\UserConsent\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class UserConsentAgreementResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function agreement(): UserConsentAgreementItemResult + { + return new UserConsentAgreementItemResult($this->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..7778443b --- /dev/null +++ b/src/Services/UserConsent/Result/UserConsentAgreementTextItemResult.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\UserConsent\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; + +/** + * Class UserConsentAgreementTextItemResult + * + * @property-read string $LABEL + * @property-read string $TEXT + */ +class UserConsentAgreementTextItemResult extends AbstractItem +{ +} \ No newline at end of file diff --git a/src/Services/UserConsent/Result/UserConsentAgreementTextResult.php b/src/Services/UserConsent/Result/UserConsentAgreementTextResult.php new file mode 100644 index 00000000..647b8e21 --- /dev/null +++ b/src/Services/UserConsent/Result/UserConsentAgreementTextResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\UserConsent\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class UserConsentAgreementTextResult extends AbstractResult +{ + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function text(): UserConsentAgreementTextItemResult + { + return new UserConsentAgreementTextItemResult($this->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..be4ce952 --- /dev/null +++ b/src/Services/UserConsent/Result/UserConsentAgreementsResult.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\UserConsent\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class UserConsentAgreementsResult extends AbstractResult +{ + /** + * @return \Bitrix24\SDK\Services\UserConsent\Result\UserConsentAgreementItemResult[] + * @throws BaseException + */ + public function getAgreements(): array + { + $res = []; + foreach ($this->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..95eac67d --- /dev/null +++ b/src/Services/UserConsent/Service/UserConsent.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\UserConsent\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\AddedItemResult; +use Bitrix24\SDK\Services\AbstractService; +#[ApiServiceMetadata(new Scope(['userconsent']))] +class UserConsent extends AbstractService +{ + /** + * Add the received user agreement consent + * + * @see https://training.bitrix24.com/rest_help/userconsent/userconsent_consent_add.php + * + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'userconsent.consent.add', + 'https://training.bitrix24.com/rest_help/userconsent/userconsent_consent_add.php', + 'Add the received user agreement consent' + )] + public function add(array $consentFields): AddedItemResult + { + return new AddedItemResult($this->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..b4c97b81 --- /dev/null +++ b/src/Services/UserConsent/Service/UserConsentAgreement.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\UserConsent\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\UserConsent\Result\UserConsentAgreementsResult; +use Bitrix24\SDK\Services\UserConsent\Result\UserConsentAgreementTextResult; +#[ApiServiceMetadata(new Scope(['userconsent']))] +class UserConsentAgreement extends AbstractService +{ + /** + * Get user consent agreement list + * + * @throws BaseException + * @throws TransportException + */ + #[ApiEndpointMetadata( + 'userconsent.agreement.list', + 'https://training.bitrix24.com/rest_help/userconsent/userconsent_consent_add.php', + 'Add the received user agreement consent' + )] + public function list(): UserConsentAgreementsResult + { + return new UserConsentAgreementsResult($this->core->call('userconsent.agreement.list')); + } + + /** + * @throws TransportException + * @throws InvalidArgumentException + * @throws BaseException + */ + #[ApiEndpointMetadata( + 'userconsent.agreement.text', + 'https://training.bitrix24.com/rest_help/userconsent/userconsent_agreement_text.php', + 'This method gets the agreement text' + )] + 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..fa6cb423 --- /dev/null +++ b/src/Services/UserConsent/UserConsentServiceBuilder.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\UserConsent; + +use Bitrix24\SDK\Services\AbstractServiceBuilder; +use Bitrix24\SDK\Services\UserConsent\Service\UserConsent; +use Bitrix24\SDK\Services\UserConsent\Service\UserConsentAgreement; + +class UserConsentServiceBuilder extends AbstractServiceBuilder +{ + /** + * get user consent agreement service + */ + public function UserConsentAgreement(): UserConsentAgreement + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new UserConsentAgreement($this->core, $this->log); + } + + return $this->serviceCache[__METHOD__]; + } + + /** + * get user consent service + */ + 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/src/Services/Workflows/Activity/Result/AddedActivityResult.php b/src/Services/Workflows/Activity/Result/AddedActivityResult.php new file mode 100644 index 00000000..0c786929 --- /dev/null +++ b/src/Services/Workflows/Activity/Result/AddedActivityResult.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Activity\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class AddedActivityResult extends AbstractResult +{ + public function isSuccess(): bool + { + return $this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Activity/Result/AddedMessageToLogResult.php b/src/Services/Workflows/Activity/Result/AddedMessageToLogResult.php new file mode 100644 index 00000000..fc5e0201 --- /dev/null +++ b/src/Services/Workflows/Activity/Result/AddedMessageToLogResult.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Activity\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class AddedMessageToLogResult extends AbstractResult +{ + public function isSuccess(): bool + { + return $this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Activity/Result/UpdateActivityResult.php b/src/Services/Workflows/Activity/Result/UpdateActivityResult.php new file mode 100644 index 00000000..e370949e --- /dev/null +++ b/src/Services/Workflows/Activity/Result/UpdateActivityResult.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Activity\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class UpdateActivityResult extends AbstractResult +{ + public function isSuccess(): bool + { + return $this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Activity/Result/WorkflowActivitiesResult.php b/src/Services/Workflows/Activity/Result/WorkflowActivitiesResult.php new file mode 100644 index 00000000..aef541fd --- /dev/null +++ b/src/Services/Workflows/Activity/Result/WorkflowActivitiesResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Activity\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class WorkflowActivitiesResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function getActivities(): array + { + return $this->getCoreResponse()->getResponseData()->getResult(); + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Activity/Service/Activity.php b/src/Services/Workflows/Activity/Service/Activity.php new file mode 100644 index 00000000..b6f94f75 --- /dev/null +++ b/src/Services/Workflows/Activity/Service/Activity.php @@ -0,0 +1,235 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Activity\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\DeletedItemResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Workflows; +use Bitrix24\SDK\Services\Workflows\Activity\Result\AddedActivityResult; +use Bitrix24\SDK\Services\Workflows\Activity\Result\AddedMessageToLogResult; +use Bitrix24\SDK\Services\Workflows\Activity\Result\UpdateActivityResult; +use Bitrix24\SDK\Services\Workflows\Common\WorkflowDocumentType; +use Psr\Log\LoggerInterface; +#[ApiServiceMetadata(new Scope(['bizproc']))] +class Activity extends AbstractService +{ + public function __construct( + public Batch $batch, + CoreInterface $core, + LoggerInterface $log + ) + { + parent::__construct($core, $log); + } + + /** + * This method records data in the workflow log. + * @return AddedMessageToLogResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/app_activities/bizproc_activity_list.php + */ + #[ApiEndpointMetadata( + 'bizproc.activity.log', + 'https://training.bitrix24.com/rest_help/workflows/app_activities/bizproc_activity_list.php', + 'This method records data in the workflow log.' + )] + public function log(string $eventToken, string $message): Workflows\Activity\Result\AddedMessageToLogResult + { + return new Workflows\Activity\Result\AddedMessageToLogResult($this->core->call('bizproc.activity.log', [ + 'EVENT_TOKEN' => $eventToken, + 'LOG_MESSAGE' => $message + ])); + } + + /** + * This method returns list of activities, installed by the application. + * + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/app_activities/bizproc_activity_list.php + */ + #[ApiEndpointMetadata( + 'bizproc.activity.list', + 'https://training.bitrix24.com/rest_help/workflows/app_activities/bizproc_activity_list.php', + 'This method returns list of activities, installed by the application.' + )] + public function list(): Workflows\Activity\Result\WorkflowActivitiesResult + { + return new Workflows\Activity\Result\WorkflowActivitiesResult($this->core->call('bizproc.activity.list')); + } + + /** + * Adds new activity to a workflow. + * + * @param string $code Internal activity ID, unique within the application framework. Permissible symbols are a-z, A-Z, 0-9, period, hyphen and underscore. + * @param string $handlerUrl URL, to which the activity will send data (via bitrix24 queue server), when workflow has reached its completion. Shall reference to the same domain, where the app is installed. + * @param int $b24AuthUserId ID of the user, whose token will be passed to the application. + * @param array $localizedName Name of activity, associative array of localized strings. + * @param array $localizedDescription Description of activity, associative array of localized strings. + * @param bool $isUseSubscription Use of subscription. It is possible to specify, whether the activity should or should not await for a response from the application. If the parameter is empty or not specified - user himself/herself can configure this parameter in settings of the activity in the workflows designer. + * @param array $properties Array of activity parameters. + * @param bool $isUsePlacement Enables option to open additional settings for activity in the app slider. + * @param array $returnProperties Array of returned activity values. + * @param WorkflowDocumentType $documentType Tip of document, which will determine type of data for parameters. + * @param array $limitationFilter Activity limitation rules by document type and revision. + * + * @return AddedActivityResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/app_activities/bizproc_activity_add.php + */ + #[ApiEndpointMetadata( + 'bizproc.activity.add', + 'https://training.bitrix24.com/rest_help/workflows/app_activities/bizproc_activity_add.php', + 'Adds new activity to a workflow.' + )] + public function add( + string $code, + string $handlerUrl, + int $b24AuthUserId, + array $localizedName, + array $localizedDescription, + bool $isUseSubscription, + array $properties, + bool $isUsePlacement, + array $returnProperties, + Workflows\Common\WorkflowDocumentType $documentType, + array $limitationFilter, + ): Workflows\Activity\Result\AddedActivityResult + { + return new Workflows\Activity\Result\AddedActivityResult($this->core->call('bizproc.activity.add', [ + 'CODE' => $code, + 'HANDLER' => $handlerUrl, + 'AUTH_USER_ID' => $b24AuthUserId, + 'NAME' => $localizedName, + 'DESCRIPTION' => $localizedDescription, + 'USE_SUBSCRIPTION' => $isUseSubscription ? 'Y' : 'N', + 'PROPERTIES' => $properties, + 'USE_PLACEMENT' => $isUsePlacement ? 'Y' : 'N', + 'RETURN_PROPERTIES' => $returnProperties, + 'DOCUMENT_TYPE' => $documentType->toArray(), + 'FILTER' => $limitationFilter + ])); + } + + /** + * This method deletes an activity. + * + * @return DeletedItemResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/app_activities/bizproc_activity_delete.php + */ + #[ApiEndpointMetadata( + 'bizproc.activity.delete', + 'https://training.bitrix24.com/rest_help/workflows/app_activities/bizproc_activity_delete.php', + 'This method deletes an activity.' + )] + public function delete(string $activityCode): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call('bizproc.activity.delete', [ + 'CODE' => $activityCode + ])); + } + + /** + * This method allows to update activity fields. Method parameters are similar to bizproc.activity.add. + * + * @param string $code Internal activity ID, unique within the application framework. Permissible symbols are a-z, A-Z, 0-9, period, hyphen and underscore. + * @param string|null $handlerUrl URL, to which the activity will send data (via bitrix24 queue server), when workflow has reached its completion. Shall reference to the same domain, where the app is installed. + * @param int|null $b24AuthUserId ID of the user, whose token will be passed to the application. + * @param array|null $localizedName Name of activity, associative array of localized strings. + * @param array|null $localizedDescription Description of activity, associative array of localized strings. + * @param bool|null $isUseSubscription Use of subscription. It is possible to specify, whether the activity should or should not await for a response from the application. If the parameter is empty or not specified - user himself/herself can configure this parameter in settings of the activity in the workflows designer. + * @param array|null $properties Array of activity parameters. + * @param bool|null $isUsePlacement Enables option to open additional settings for activity in the app slider. + * @param array|null $returnProperties Array of returned activity values. + * @param WorkflowDocumentType|null $documentType Tip of document, which will determine type of data for parameters. + * @param array|null $limitationFilter Activity limitation rules by document type and revision. + * + * @return UpdateActivityResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/app_activities/bizproc_activity_update.php + */ + #[ApiEndpointMetadata( + 'bizproc.activity.update', + 'https://training.bitrix24.com/rest_help/workflows/app_activities/bizproc_activity_update.php', + 'This method allows to update activity fields. Method parameters are similar to bizproc.activity.add.' + )] + public function update( + string $code, + ?string $handlerUrl, + ?int $b24AuthUserId, + ?array $localizedName, + ?array $localizedDescription, + ?bool $isUseSubscription, + ?array $properties, + ?bool $isUsePlacement, + ?array $returnProperties, + ?Workflows\Common\WorkflowDocumentType $documentType, + ?array $limitationFilter, + ): Workflows\Activity\Result\UpdateActivityResult + { + $fieldsToUpdate = []; + if ($handlerUrl !== null) { + $fieldsToUpdate['HANDLER'] = $handlerUrl; + } + if ($b24AuthUserId !== null) { + $fieldsToUpdate['AUTH_USER_ID'] = $b24AuthUserId; + } + if ($localizedName !== null) { + $fieldsToUpdate['NAME'] = $localizedName; + } + if ($localizedDescription !== null) { + $fieldsToUpdate['DESCRIPTION'] = $localizedDescription; + } + if ($isUseSubscription !== null) { + $fieldsToUpdate['USE_SUBSCRIPTION'] = $isUseSubscription ? 'Y' : 'N'; + } + if ($properties !== null) { + $fieldsToUpdate['PROPERTIES'] = $properties; + } + if ($isUsePlacement !== null) { + $fieldsToUpdate['USE_PLACEMENT'] = $isUsePlacement ? 'Y' : 'N'; + } + if ($returnProperties !== null) { + $fieldsToUpdate['RETURN_PROPERTIES'] = $returnProperties; + } + if ($documentType !== null) { + $fieldsToUpdate['DOCUMENT_TYPE'] = $documentType->toArray(); + } + if ($limitationFilter !== null) { + $fieldsToUpdate['FILTER'] = $limitationFilter; + } + if (count($fieldsToUpdate) === 0) { + throw new InvalidArgumentException('no fields to update – you must set minimum one field to update'); + } + return new Workflows\Activity\Result\UpdateActivityResult($this->core->call( + 'bizproc.activity.update', + [ + 'CODE' => $code, + 'FIELDS' => $fieldsToUpdate + ])); + } +} diff --git a/src/Services/Workflows/Activity/Service/Batch.php b/src/Services/Workflows/Activity/Service/Batch.php new file mode 100644 index 00000000..aa6ee33a --- /dev/null +++ b/src/Services/Workflows/Activity/Service/Batch.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Activity\Service; + +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +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 Generator; +use Psr\Log\LoggerInterface; + +readonly class Batch +{ + public function __construct( + protected BatchOperationsInterface $batch, + protected LoggerInterface $log) + { + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Common/Auth.php b/src/Services/Workflows/Common/Auth.php new file mode 100644 index 00000000..8988357f --- /dev/null +++ b/src/Services/Workflows/Common/Auth.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Common; + +use Bitrix24\SDK\Application\ApplicationStatus; +use Bitrix24\SDK\Core\Credentials\AuthToken; +use Bitrix24\SDK\Core\Credentials\Endpoints; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException; + +readonly class Auth +{ + public function __construct( + public AuthToken $accessToken, + public Endpoints $endpoints, + public Scope $scope, + public ApplicationStatus $applicationStatus, + public string $applicationToken, + public int $expiresIn, + public string $domain, + public string $memberId, + public int $userId + ) + { + } + + /** + * @throws UnknownScopeCodeException + * @throws InvalidArgumentException + */ + public static function initFromArray(array $auth): self + { + return new self( + AuthToken::initFromArray($auth), + Endpoints::initFromArray($auth), + Scope::initFromString($auth['scope']), + ApplicationStatus::initFromString($auth['status']), + $auth['application_token'], + (int)$auth['expires_in'], + $auth['domain'], + $auth['member_id'], + (int)$auth['user_id'] + ); + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Common/DocumentType.php b/src/Services/Workflows/Common/DocumentType.php new file mode 100644 index 00000000..3bca1e40 --- /dev/null +++ b/src/Services/Workflows/Common/DocumentType.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Common; + +enum DocumentType: string +{ + // lead + case crmLead = 'CCrmDocumentLead'; + // company + case crmCompany = 'CCrmDocumentCompany'; + // contact + case crmContact = 'CCrmDocumentContact'; + // deal + case crmDeal = 'CCrmDocumentDeal'; + // drive file + case discBizProcDocument = 'Bitrix\\Disk\\BizProcDocument'; + // Drive file + case listBizProcDocument = 'BizprocDocument'; + case listBizProcDocumentLists = 'BizprocDocumentLists'; + // smart process + case smartProcessDynamic = 'Bitrix\\Crm\\Integration\\BizProc\\Document\\Dynamic'; + case task = 'Bitrix\\Tasks\\Integration\\Bizproc\\Document\\Task'; + case invoice = 'Bitrix\\Crm\\Integration\\BizProc\\Document\\SmartInvoice'; +} diff --git a/src/Services/Workflows/Common/WorkflowAutoExecutionType.php b/src/Services/Workflows/Common/WorkflowAutoExecutionType.php new file mode 100644 index 00000000..1eae76bb --- /dev/null +++ b/src/Services/Workflows/Common/WorkflowAutoExecutionType.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Common; + +enum WorkflowAutoExecutionType: int +{ + case withoutAutoExecution = 0; + case whenAdded = 1; + case whenModified = 2; + case whenAddedAndModified = 3; +} diff --git a/src/Services/Workflows/Common/WorkflowDocumentId.php b/src/Services/Workflows/Common/WorkflowDocumentId.php new file mode 100644 index 00000000..63fdafbd --- /dev/null +++ b/src/Services/Workflows/Common/WorkflowDocumentId.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Common; + +readonly class WorkflowDocumentId +{ + public function __construct( + public string $moduleId, + public string $entityId, + public string $targetDocumentId, + ) + { + } + + public function getId(): int + { + return (int)substr($this->targetDocumentId, 0, strpos('_', $this->targetDocumentId)); + } + + public static function initFromArray(array $data): WorkflowDocumentId + { + return new self($data[0], $data[1], $data[2]); + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Common/WorkflowDocumentType.php b/src/Services/Workflows/Common/WorkflowDocumentType.php new file mode 100644 index 00000000..e1bbe0ca --- /dev/null +++ b/src/Services/Workflows/Common/WorkflowDocumentType.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Common; + +readonly class WorkflowDocumentType +{ + public function __construct( + public string $moduleId, + public string $entityId, + public string $targetDocumentId, + ) + { + } + + public static function initFromArray(array $data): self + { + return new self($data[0], $data[1], $data[2]); + } + + public function toArray(): array + { + return [$this->moduleId, $this->entityId, $this->targetDocumentId]; + } + + public static function buildForLead(): self + { + return new self('crm', 'CCrmDocumentLead', 'LEAD'); + } + + public static function buildForContact(): self + { + return new self('crm', 'CCrmDocumentContact', 'CONTACT'); + } + + public static function buildForDeal(): self + { + return new self('crm', 'CCrmDocumentDeal', 'Deal'); + } +} + +// ['crm', 'CCrmDocumentLead', 'LEAD'] +// ['lists', 'BizprocDocument', 'iblock_22'] +// ['disk', 'Bitrix\Disk\BizProcDocument', 'STORAGE_490'] +// ['tasks', 'Bitrix\Tasks\Integration\Bizproc\Document\Task', 'TASK_PROJECT_13'] \ No newline at end of file diff --git a/src/Services/Workflows/Common/WorkflowPropertyType.php b/src/Services/Workflows/Common/WorkflowPropertyType.php new file mode 100644 index 00000000..6ec69804 --- /dev/null +++ b/src/Services/Workflows/Common/WorkflowPropertyType.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Common; + +enum WorkflowPropertyType: string +{ + case bool = 'bool'; + case date = 'date'; + case datetime = 'datetime'; + case double = 'double'; + case int = 'int'; + case select = 'select'; + case string = 'string'; + case text = 'text'; + case user = 'user'; +} \ No newline at end of file diff --git a/src/Services/Workflows/Common/WorkflowTaskActivityType.php b/src/Services/Workflows/Common/WorkflowTaskActivityType.php new file mode 100644 index 00000000..76945f80 --- /dev/null +++ b/src/Services/Workflows/Common/WorkflowTaskActivityType.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Common; + +enum WorkflowTaskActivityType: string +{ + case approveActivity = 'ApproveActivity'; + case reviewActivity = 'ReviewActivity'; + case requestInformationActivity = 'RequestInformationActivity'; + case requestInformationOptionalActivity = 'RequestInformationOptionalActivity'; +} \ No newline at end of file diff --git a/src/Services/Workflows/Common/WorkflowTaskCompleteStatusType.php b/src/Services/Workflows/Common/WorkflowTaskCompleteStatusType.php new file mode 100644 index 00000000..52d5622b --- /dev/null +++ b/src/Services/Workflows/Common/WorkflowTaskCompleteStatusType.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Common; + +enum WorkflowTaskCompleteStatusType: int +{ + case approved = 1; + case rejected = 2; + case reviewed = 3; + case cancelled = 4; +} \ No newline at end of file diff --git a/src/Services/Workflows/Common/WorkflowTaskStatusType.php b/src/Services/Workflows/Common/WorkflowTaskStatusType.php new file mode 100644 index 00000000..9389ddca --- /dev/null +++ b/src/Services/Workflows/Common/WorkflowTaskStatusType.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Common; + +enum WorkflowTaskStatusType: int +{ + case inProgress = 0; + case approved = 1; + case rejected = 2; + case completed = 3; + case timeOut = 4; +} \ No newline at end of file diff --git a/src/Services/Workflows/Common/WorkflowTaskUserStatusType.php b/src/Services/Workflows/Common/WorkflowTaskUserStatusType.php new file mode 100644 index 00000000..d0fc40df --- /dev/null +++ b/src/Services/Workflows/Common/WorkflowTaskUserStatusType.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Common; + +enum WorkflowTaskUserStatusType: int +{ + case waitingForResponse = 0; + case approved = 1; + case rejected = 2; + case completed = 3; +} \ No newline at end of file diff --git a/src/Services/Workflows/Event/Result/EventSendResult.php b/src/Services/Workflows/Event/Result/EventSendResult.php new file mode 100644 index 00000000..32b87ee7 --- /dev/null +++ b/src/Services/Workflows/Event/Result/EventSendResult.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Event\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class EventSendResult extends AbstractResult +{ + public function isSuccess(): bool + { + return $this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Event/Service/Batch.php b/src/Services/Workflows/Event/Service/Batch.php new file mode 100644 index 00000000..9252244d --- /dev/null +++ b/src/Services/Workflows/Event/Service/Batch.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Event\Service; + +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +use Psr\Log\LoggerInterface; + +readonly class Batch +{ + public function __construct( + protected BatchOperationsInterface $batch, + protected LoggerInterface $log) + { + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Event/Service/Event.php b/src/Services/Workflows/Event/Service/Event.php new file mode 100644 index 00000000..7cbe4eba --- /dev/null +++ b/src/Services/Workflows/Event/Service/Event.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Event\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Workflows; +use Psr\Log\LoggerInterface; +#[ApiServiceMetadata(new Scope(['bizproc']))] +class Event extends AbstractService +{ + public function __construct( + public Batch $batch, + CoreInterface $core, + LoggerInterface $log + ) + { + parent::__construct($core, $log); + } + + /** + * returns output parameters to an activity. Parameters are specified in the activity description. + * + * @return Workflows\Event\Result\EventSendResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/workflows_events/bizproc_event_send.php + */ + #[ApiEndpointMetadata( + 'bizproc.event.send', + 'https://training.bitrix24.com/rest_help/workflows/workflows_events/bizproc_event_send.php', + 'returns output parameters to an activity. Parameters are specified in the activity description.' + )] + public function send( + string $eventToken, + array $returnValues, + ?string $logMessage = null, + ): Workflows\Event\Result\EventSendResult + { + return new Workflows\Event\Result\EventSendResult($this->core->call( + 'bizproc.event.send', + [ + 'event_token' => $eventToken, + 'return_values' => $returnValues, + 'log_message' => $logMessage + ] + )); + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Exceptions/ActivityOrRobotAlreadyInstalledException.php b/src/Services/Workflows/Exceptions/ActivityOrRobotAlreadyInstalledException.php new file mode 100644 index 00000000..c6574be2 --- /dev/null +++ b/src/Services/Workflows/Exceptions/ActivityOrRobotAlreadyInstalledException.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Workflows\Exceptions; + +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; + +class ActivityOrRobotAlreadyInstalledException extends InvalidArgumentException +{ +} \ No newline at end of file diff --git a/src/Services/Workflows/Exceptions/ActivityOrRobotValidationFailureException.php b/src/Services/Workflows/Exceptions/ActivityOrRobotValidationFailureException.php new file mode 100644 index 00000000..2dd24998 --- /dev/null +++ b/src/Services/Workflows/Exceptions/ActivityOrRobotValidationFailureException.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Workflows\Exceptions; + +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; + +class ActivityOrRobotValidationFailureException extends InvalidArgumentException +{ +} \ No newline at end of file diff --git a/src/Services/Workflows/Exceptions/WorkflowTaskAlreadyCompletedException.php b/src/Services/Workflows/Exceptions/WorkflowTaskAlreadyCompletedException.php new file mode 100644 index 00000000..af26237f --- /dev/null +++ b/src/Services/Workflows/Exceptions/WorkflowTaskAlreadyCompletedException.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Services\Workflows\Exceptions; + +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; + +class WorkflowTaskAlreadyCompletedException extends InvalidArgumentException +{ +} \ No newline at end of file diff --git a/src/Services/Workflows/Robot/Request/IncomingRobotRequest.php b/src/Services/Workflows/Robot/Request/IncomingRobotRequest.php new file mode 100644 index 00000000..859d9a64 --- /dev/null +++ b/src/Services/Workflows/Robot/Request/IncomingRobotRequest.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Robot\Request; + +use Bitrix24\SDK\Application\Requests\AbstractRequest; +use Bitrix24\SDK\Services\Workflows\Common\Auth; +use Bitrix24\SDK\Services\Workflows\Common\WorkflowDocumentId; +use Bitrix24\SDK\Services\Workflows\Common\WorkflowDocumentType; +use Symfony\Component\HttpFoundation\Request; + +class IncomingRobotRequest extends AbstractRequest +{ + public function __construct( + Request $request, + readonly public string $workflowId, + readonly public string $code, + readonly public WorkflowDocumentId $workflowDocumentId, + readonly public WorkflowDocumentType $workflowDocumentType, + readonly public string $eventToken, + readonly public array $properties, + readonly public bool $isUseSubscription, + readonly public int $timeoutDuration, + readonly public int $timestamp, + readonly public Auth $auth + ) + { + parent::__construct($request); + } + + public static function initFromRequest(Request $request): self + { + $data = $request->request->all(); + return new self( + $request, + (string)$data['workflow_id'], + $data['code'], + WorkflowDocumentId::initFromArray($data['document_id']), + WorkflowDocumentType::initFromArray($data['document_type']), + $data['event_token'], + $data['properties'], + $data['use_subscription'] === 'Y' ? true : false, + (int)$data['timeout_duration'], + (int)$data['ts'], + Auth::initFromArray($data['auth']) + ); + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Robot/Result/AddedRobotResult.php b/src/Services/Workflows/Robot/Result/AddedRobotResult.php new file mode 100644 index 00000000..5888cb64 --- /dev/null +++ b/src/Services/Workflows/Robot/Result/AddedRobotResult.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Robot\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class AddedRobotResult extends AbstractResult +{ + public function isSuccess(): bool + { + return $this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Robot/Result/UpdateRobotResult.php b/src/Services/Workflows/Robot/Result/UpdateRobotResult.php new file mode 100644 index 00000000..5e7615d9 --- /dev/null +++ b/src/Services/Workflows/Robot/Result/UpdateRobotResult.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Robot\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class UpdateRobotResult extends AbstractResult +{ + public function isSuccess(): bool + { + return $this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Robot/Result/WorkflowRobotsResult.php b/src/Services/Workflows/Robot/Result/WorkflowRobotsResult.php new file mode 100644 index 00000000..c2145357 --- /dev/null +++ b/src/Services/Workflows/Robot/Result/WorkflowRobotsResult.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Robot\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class WorkflowRobotsResult extends AbstractResult +{ + /** + * @throws BaseException + */ + public function getRobots(): array + { + return $this->getCoreResponse()->getResponseData()->getResult(); + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Robot/Service/Robot.php b/src/Services/Workflows/Robot/Service/Robot.php new file mode 100644 index 00000000..be7c4f20 --- /dev/null +++ b/src/Services/Workflows/Robot/Service/Robot.php @@ -0,0 +1,176 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Robot\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\DeletedItemResult; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Workflows; +use Bitrix24\SDK\Services\Workflows\Robot\Result\AddedRobotResult; +use Bitrix24\SDK\Services\Workflows\Robot\Result\UpdateRobotResult; +use Bitrix24\SDK\Services\Workflows\Template\Service\Batch; +use Psr\Log\LoggerInterface; + +#[ApiServiceMetadata(new Scope(['bizproc']))] +class Robot extends AbstractService +{ + public function __construct( + public Batch $batch, + CoreInterface $core, + LoggerInterface $log + ) + { + parent::__construct($core, $log); + } + + /** + * Registers new automation rule. + * + * + * @return AddedRobotResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/app_automation_rules/bizproc_robot_add.php + */ + #[ApiEndpointMetadata( + 'bizproc.robot.add', + 'https://training.bitrix24.com/rest_help/workflows/app_automation_rules/bizproc_robot_add.php', + 'Registers new automation rule.' + )] + public function add( + string $code, + string $handlerUrl, + int $b24AuthUserId, + array $localizedRobotName, + bool $isUseSubscription, + array $properties, + bool $isUsePlacement, + array $returnProperties + ): Workflows\Robot\Result\AddedRobotResult + { + return new Workflows\Robot\Result\AddedRobotResult($this->core->call('bizproc.robot.add', [ + 'CODE' => $code, + 'HANDLER' => $handlerUrl, + 'AUTH_USER_ID' => $b24AuthUserId, + 'NAME' => $localizedRobotName, + 'USE_SUBSCRIPTION' => $isUseSubscription ? 'Y' : 'N', + 'PROPERTIES' => $properties, + 'USE_PLACEMENT' => $isUsePlacement ? 'Y' : 'N', + 'RETURN_PROPERTIES' => $returnProperties + ])); + } + + /** + * This method returns list of automation rules, registered by the application. + * + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/app_automation_rules/bizproc_robot_list.php + */ + #[ApiEndpointMetadata( + 'bizproc.robot.list', + 'https://training.bitrix24.com/rest_help/workflows/app_automation_rules/bizproc_robot_list.php', + 'This method returns list of automation rules, registered by the application.' + )] + public function list(): Workflows\Robot\Result\WorkflowRobotsResult + { + return new Workflows\Robot\Result\WorkflowRobotsResult($this->core->call('bizproc.robot.list')); + } + + /** + * This method deletes registered automation rule. + * + * @return DeletedItemResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/app_automation_rules/bizproc_robot_delete.php + */ + #[ApiEndpointMetadata( + 'bizproc.robot.delete', + 'https://training.bitrix24.com/rest_help/workflows/app_automation_rules/bizproc_robot_delete.php', + 'This method deletes registered automation rule.' + )] + public function delete(string $robotCode): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call('bizproc.robot.delete', [ + 'CODE' => $robotCode + ])); + } + + /** + * updates fields of automation rules + * + * @param bool $isUseSubscription + * @param bool $isUsePlacement + * @return UpdateRobotResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/app_automation_rules/bizproc_robot_update.php + */ + #[ApiEndpointMetadata( + 'bizproc.robot.update', + 'https://training.bitrix24.com/rest_help/workflows/app_automation_rules/bizproc_robot_update.php', + 'updates fields of automation rules' + )] + public function update( + string $code, + ?string $handlerUrl = null, + ?int $b24AuthUserId = null, + ?array $localizedRobotName = null, + ?bool $isUseSubscription = null, + ?array $properties = null, + ?bool $isUsePlacement = null, + ?array $returnProperties = null + ): Workflows\Robot\Result\UpdateRobotResult + { + $fieldsToUpdate = []; + if ($handlerUrl !== null) { + $fieldsToUpdate['HANDLER'] = $handlerUrl; + } + if ($b24AuthUserId !== null) { + $fieldsToUpdate['AUTH_USER_ID'] = $b24AuthUserId; + } + if ($localizedRobotName !== null) { + $fieldsToUpdate['NAME'] = $localizedRobotName; + } + if ($isUseSubscription !== null) { + $fieldsToUpdate['USE_SUBSCRIPTION'] = $isUseSubscription ? 'Y' : 'N'; + } + if ($properties !== null) { + $fieldsToUpdate['PROPERTIES'] = $properties; + } + if ($isUsePlacement !== null) { + $fieldsToUpdate['USE_PLACEMENT'] = $isUsePlacement ? 'Y' : 'N'; + } + if ($returnProperties !== null) { + $fieldsToUpdate['RETURN_PROPERTIES'] = $returnProperties; + } + if (count($fieldsToUpdate) === 0) { + throw new InvalidArgumentException('no fields to update – you must set minimum one field to update'); + } + return new Workflows\Robot\Result\UpdateRobotResult($this->core->call( + 'bizproc.robot.update', + [ + 'CODE' => $code, + 'FIELDS' => $fieldsToUpdate + ])); + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Task/Result/WorkflowTaskCompleteResult.php b/src/Services/Workflows/Task/Result/WorkflowTaskCompleteResult.php new file mode 100644 index 00000000..278b63cf --- /dev/null +++ b/src/Services/Workflows/Task/Result/WorkflowTaskCompleteResult.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Task\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class WorkflowTaskCompleteResult extends AbstractResult +{ + public function isSuccess(): bool + { + return $this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Task/Result/WorkflowTaskItemResult.php b/src/Services/Workflows/Task/Result/WorkflowTaskItemResult.php new file mode 100644 index 00000000..10ba5eca --- /dev/null +++ b/src/Services/Workflows/Task/Result/WorkflowTaskItemResult.php @@ -0,0 +1,96 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Task\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; +use Bitrix24\SDK\Services\Workflows\Common\DocumentType; +use Bitrix24\SDK\Services\Workflows\Common\WorkflowAutoExecutionType; +use Bitrix24\SDK\Services\Workflows\Common\WorkflowTaskActivityType; +use Bitrix24\SDK\Services\Workflows\Common\WorkflowTaskStatusType; +use Bitrix24\SDK\Services\Workflows\Common\WorkflowTaskUserStatusType; +use Carbon\CarbonImmutable; + +/** + * @property-read int $ID task ID + * @property-read ?string $WORKFLOW_ID workflow ID + * @property-read ?string $DOCUMENT_NAME document name + * @property-read ?string $DESCRIPTION task description + * @property-read ?string $NAME task name + * @property-read ?CarbonImmutable $MODIFIED date of modification + * @property-read ?CarbonImmutable $WORKFLOW_STARTED date of workflow launch + * @property-read ?int $WORKFLOW_STARTED_BY who launched the workflow + * @property-read ?CarbonImmutable $OVERDUE_DATE deadline + * @property-read ?int $WORKFLOW_TEMPLATE_ID workflow template ID + * @property-read ?string $WORKFLOW_TEMPLATE_NAME workflow template name + * @property-read ?string $WORKFLOW_STATE workflow status description + * @property-read ?WorkflowTaskStatusType $STATUS task status + * @property-read ?int $USER_ID user id + * @property-read ?WorkflowTaskUserStatusType $USER_STATUS user response status + * @property-read ?string $MODULE_ID module id (for document) + * @property-read ?DocumentType $ENTITY entity ID (for document) + * @property-read ?int $DOCUMENT_ID document ID + * @property-read ?WorkflowTaskActivityType $ACTIVITY task type ID + * @property-read ?array $PARAMETERS task parameters + * @property-read ?string $DOCUMENT_URL document URL + */ +class WorkflowTaskItemResult extends AbstractItem +{ + public function __get($offset) + { + switch ($offset) { + case 'ID': + case 'WORKFLOW_TEMPLATE_ID': + case 'USER_ID': + return (int)$this->data[$offset]; + case 'DOCUMENT_ID': + if ($this->data[$offset] !== '') { + return (int)substr((string) $this->data[$offset], strrpos((string) $this->data[$offset], '_') + 1); + } + return null; + case 'MODIFIED': + case 'WORKFLOW_STARTED': + case 'OVERDUE_DATE': + if ($this->data[$offset] !== '') { + return CarbonImmutable::createFromFormat(DATE_ATOM, $this->data[$offset]); + } + return null; + case 'STATUS': + if ($this->data[$offset] !== '') { + return WorkflowTaskStatusType::from((int)$this->data[$offset]); + } + return null; + case 'USER_STATUS': + if ($this->data[$offset] !== '') { + return WorkflowTaskUserStatusType::from((int)$this->data[$offset]); + } + return null; + case 'ENTITY': + if ($this->data[$offset] !== '') { + return DocumentType::from($this->data[$offset]); + } + return null; + case 'ACTIVITY': + if ($this->data[$offset] !== '') { + return WorkflowTaskActivityType::from($this->data[$offset]); + } + return null; + case 'PARAMETERS': + if ($this->data[$offset] !== '') { + return $this->data[$offset]; + } + return null; + } + return $this->data[$offset] ?? null; + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Task/Result/WorkflowTasksResult.php b/src/Services/Workflows/Task/Result/WorkflowTasksResult.php new file mode 100644 index 00000000..e4be2947 --- /dev/null +++ b/src/Services/Workflows/Task/Result/WorkflowTasksResult.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Task\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class WorkflowTasksResult extends AbstractResult +{ + /** + * @return WorkflowTaskItemResult[] + * @throws BaseException + */ + public function getTasks(): array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { + $res[] = new WorkflowTaskItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Task/Service/Batch.php b/src/Services/Workflows/Task/Service/Batch.php new file mode 100644 index 00000000..8a3b0d25 --- /dev/null +++ b/src/Services/Workflows/Task/Service/Batch.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Task\Service; + +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +use Psr\Log\LoggerInterface; + +readonly class Batch +{ + public function __construct( + protected BatchOperationsInterface $batch, + protected LoggerInterface $log) + { + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Task/Service/Task.php b/src/Services/Workflows/Task/Service/Task.php new file mode 100644 index 00000000..ccbb226e --- /dev/null +++ b/src/Services/Workflows/Task/Service/Task.php @@ -0,0 +1,144 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Task\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Workflows\Common\DocumentType; +use Bitrix24\SDK\Services\Workflows\Common\WorkflowTaskActivityType; +use Bitrix24\SDK\Services\Workflows\Common\WorkflowTaskCompleteStatusType; +use Bitrix24\SDK\Services\Workflows\Common\WorkflowTaskStatusType; +use Bitrix24\SDK\Services\Workflows\Common\WorkflowTaskUserStatusType; +use Bitrix24\SDK\Services\Workflows\Task\Result\WorkflowTaskCompleteResult; +use Carbon\CarbonImmutable; +use Psr\Log\LoggerInterface; +use Bitrix24\SDK\Services\Workflows\Task\Result\WorkflowTasksResult; +#[ApiServiceMetadata(new Scope(['bizproc']))] +class Task extends AbstractService +{ + public function __construct( + public Batch $batch, + CoreInterface $core, + LoggerInterface $log + ) + { + parent::__construct($core, $log); + } + + /** + * Complete workflow task + * + * Presently, the tasks Document approval and Document review can be executed. + * Only your own task can be completed, as well as the task, not completed yet. + * + * Starting from the Business Process module version 20.0.800 you have an option to execute Request for extra information. + * You can execute only your task and only when it wasn't executed yet. + * + * @return WorkflowTaskCompleteResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/workflows_tasks/bizproc_task_complete.php + */ + #[ApiEndpointMetadata( + 'bizproc.task.complete', + 'https://training.bitrix24.com/rest_help/workflows/workflows_tasks/bizproc_task_complete.php', + 'Complete workflow task' + )] + public function complete(int $taskId, WorkflowTaskCompleteStatusType $status, string $comment, ?array $taskFields = null): WorkflowTaskCompleteResult + { + return new WorkflowTaskCompleteResult($this->core->call('bizproc.task.complete', [ + 'TASK_ID' => $taskId, + 'STATUS' => $status->value, + 'COMMENT' => $comment, + 'FIELDS' => $taskFields + ])); + } + + /** + * List of workflow tasks + * + * Not only administrators can access this method. Usual user can request his/her own tasks or tasks of his/her subordinate. + * To request personal tasks, non-administrator should not specify filter for USER_ID + * + * @param array|array{ + * ID?:int, + * WORKFLOW_ID?:string, + * DOCUMENT_NAME?:string, + * DESCRIPTION?:string, + * NAME?:string, + * MODIFIED?: CarbonImmutable, + * WORKFLOW_STARTED?: CarbonImmutable, + * WORKFLOW_STARTED_BY?: int, + * OVERDUE_DATE?: CarbonImmutable, + * WORKFLOW_TEMPLATE_ID?:int, + * WORKFLOW_TEMPLATE_NAME?:string, + * WORKFLOW_STATE?: string, + * STATUS?:WorkflowTaskStatusType, + * USER_ID?:int, + * USER_STATUS?:WorkflowTaskUserStatusType, + * MODULE_ID?:string, + * ENTITY?:DocumentType, + * DOCUMENT_ID?:int, + * ACTIVITY: WorkflowTaskActivityType, + * PARAMETERS?:array, + * DOCUMENT_URL?:string } $filter + * @param array|array{ + * 'ID', + * 'WORKFLOW_ID', + * 'DOCUMENT_NAME', + * 'NAME', + * 'DESCRIPTION', + * 'MODIFIED', + * 'WORKFLOW_STARTED', + * 'WORKFLOW_STARTED_BY', + * 'OVERDUE_DATE', + * 'WORKFLOW_TEMPLATE_ID', + * 'WORKFLOW_TEMPLATE_NAME', + * 'WORKFLOW_STATE', + * 'STATUS', + * 'USER_ID', + * 'USER_STATUS', + * 'MODULE_ID', + * 'ENTITY', + * 'DOCUMENT_ID', + * 'ACTIVITY', + * 'PARAMETERS', + * 'DOCUMENT_URL' } $select + * @return WorkflowTasksResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/workflows_tasks/bizproc_task_list.php + */ + #[ApiEndpointMetadata( + 'bizproc.task.list', + 'https://training.bitrix24.com/rest_help/workflows/workflows_tasks/bizproc_task_list.php', + 'List of workflow tasks' + )] + public function list( + array $order = ['ID' => 'DESC'], + array $filter = [], + array $select = ['ID', 'WORKFLOW_ID', 'DOCUMENT_NAME', 'NAME']): WorkflowTasksResult + { + return new WorkflowTasksResult($this->core->call('bizproc.task.list', [ + 'SELECT' => $select, + 'FILTER' => $filter, + 'ORDER' => $order + ])); + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Template/Result/WorkflowTemplateItemResult.php b/src/Services/Workflows/Template/Result/WorkflowTemplateItemResult.php new file mode 100644 index 00000000..2c3f3629 --- /dev/null +++ b/src/Services/Workflows/Template/Result/WorkflowTemplateItemResult.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Template\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; +use Bitrix24\SDK\Services\Workflows\Common\WorkflowAutoExecutionType; +use Carbon\CarbonImmutable; + +/** + * @property-read int $ID + * @property-read ?string $MODULE_ID + * @property-read ?string $ENTITY + * @property-read ?array $DOCUMENT_TYPE + * @property-read ?WorkflowAutoExecutionType $AUTO_EXECUTE + * @property-read ?string $NAME + * @property-read ?array $TEMPLATE + * @property-read ?array $PARAMETERS + * @property-read ?array $VARIABLES + * @property-read ?array $CONSTANTS + * @property-read ?CarbonImmutable $MODIFIED + * @property-read ?bool $IS_MODIFIED + * @property-read ?int $USER_ID + * @property-read ?string $SYSTEM_CODE + */ +class WorkflowTemplateItemResult extends AbstractItem +{ + public function __get($offset) + { + switch ($offset) { + case 'ID': + case 'USER_ID': + return (int)$this->data[$offset]; + case 'AUTO_EXECUTE': + if ($this->data[$offset] !== null) { + return WorkflowAutoExecutionType::from((int)$this->data[$offset]); + } + return null; + case 'MODIFIED': + if ($this->data[$offset] !== '') { + return CarbonImmutable::createFromFormat(DATE_ATOM, $this->data[$offset]); + } + return null; + case 'IS_MODIFIED': + return $this->data[$offset] === 'Y'; + } + return $this->data[$offset] ?? null; + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Template/Result/WorkflowTemplatesResult.php b/src/Services/Workflows/Template/Result/WorkflowTemplatesResult.php new file mode 100644 index 00000000..2680c618 --- /dev/null +++ b/src/Services/Workflows/Template/Result/WorkflowTemplatesResult.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Template\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class WorkflowTemplatesResult extends AbstractResult +{ + /** + * @return WorkflowTemplateItemResult[] + * @throws BaseException + */ + public function getTemplates(): array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { + $res[] = new WorkflowTemplateItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Template/Service/Batch.php b/src/Services/Workflows/Template/Service/Batch.php new file mode 100644 index 00000000..830b3e46 --- /dev/null +++ b/src/Services/Workflows/Template/Service/Batch.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Template\Service; + +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +use Psr\Log\LoggerInterface; + +readonly class Batch +{ + public function __construct( + protected BatchOperationsInterface $batch, + protected LoggerInterface $log) + { + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Template/Service/Template.php b/src/Services/Workflows/Template/Service/Template.php new file mode 100644 index 00000000..c12b9820 --- /dev/null +++ b/src/Services/Workflows/Template/Service/Template.php @@ -0,0 +1,178 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Template\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Result\AddedItemResult; +use Bitrix24\SDK\Core\Result\DeletedItemResult; +use Bitrix24\SDK\Core\Result\UpdatedItemResult; +use Bitrix24\SDK\Infrastructure\Filesystem\Base64Encoder; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Workflows; +use Psr\Log\LoggerInterface; + +#[ApiServiceMetadata(new Scope(['bizproc']))] +class Template extends AbstractService +{ + public function __construct( + public Batch $batch, + CoreInterface $core, + private readonly Base64Encoder $base64Encoder, + LoggerInterface $log + ) + { + parent::__construct($core, $log); + } + + /** + * Add a workflow template, requires administrator access permissions + * + * @return AddedItemResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/wirkflow_template/bizproc_workflow_template_add.php + */ + #[ApiEndpointMetadata( + 'bizproc.workflow.template.add', + 'https://training.bitrix24.com/rest_help/workflows/wirkflow_template/bizproc_workflow_template_add.php', + 'Add a workflow template, requires administrator access permissions' + )] + public function add( + Workflows\Common\WorkflowDocumentType $workflowDocumentType, + string $name, + string $description, + Workflows\Common\WorkflowAutoExecutionType $workflowAutoExecutionType, + string $filename + ): AddedItemResult + { + return new AddedItemResult($this->core->call('bizproc.workflow.template.add', [ + 'DOCUMENT_TYPE' => $workflowDocumentType->toArray(), + 'NAME' => $name, + 'DESCRIPTION' => $description, + 'AUTO_EXECUTE' => (string)$workflowAutoExecutionType->value, + 'TEMPLATE_DATA' => $this->base64Encoder->encodeFile($filename) + ])); + } + + /** + * Update workflow template + * + * Requires administrator access permissions. This method only updates the templates created via the method bizproc.workflow.template.add, + * because such templates are bound to a specific app. + * + * @return UpdatedItemResult + * @throws BaseException + * @throws TransportException + * @throws \Bitrix24\SDK\Core\Exceptions\FileNotFoundException + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @see https://training.bitrix24.com/rest_help/workflows/wirkflow_template/bizproc_workflow_template_update.php + */ + #[ApiEndpointMetadata( + 'bizproc.workflow.template.update', + 'https://training.bitrix24.com/rest_help/workflows/wirkflow_template/bizproc_workflow_template_update.php', + 'Update workflow template' + )] + public function update( + int $templateId, + ?Workflows\Common\WorkflowDocumentType $workflowDocumentType, + ?string $name, + ?string $description, + ?Workflows\Common\WorkflowAutoExecutionType $workflowAutoExecutionType, + ?string $filename + ) + { + $fieldsToUpdate = []; + if ($workflowDocumentType !== null) { + $fieldsToUpdate['DOCUMENT_TYPE'] = $workflowDocumentType->toArray(); + } + if ($name !== null) { + $fieldsToUpdate['NAME'] = $name; + } + if ($description !== null) { + $fieldsToUpdate['DESCRIPTION'] = $description; + } + if ($workflowAutoExecutionType !== null) { + $fieldsToUpdate['AUTO_EXECUTE'] = (string)$workflowAutoExecutionType->value; + } + if ($filename !== null) { + $fieldsToUpdate['TEMPLATE_DATA'] = $this->base64Encoder->encodeFile($filename); + } + if (count($fieldsToUpdate) === 0) { + throw new InvalidArgumentException('no fields to update – you must set minimum one field to update'); + } + + return new UpdatedItemResult($this->core->call( + 'bizproc.workflow.template.update', [ + 'ID' => $templateId, + 'FIELDS' => $fieldsToUpdate + ] + )); + } + + /** + * The method deletes workflow template. Requires the administrator access permissions. + * + * This method deletes only the templates created via the method bizproc.workflow.template.add, + * because such templates are bound to an app and only they can be deleted. + * + * @return DeletedItemResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/wirkflow_template/bizproc_workflow_template_delete.php + */ + #[ApiEndpointMetadata( + 'bizproc.workflow.template.delete', + 'https://training.bitrix24.com/rest_help/workflows/wirkflow_template/bizproc_workflow_template_delete.php', + 'The method deletes workflow template. Requires the administrator access permissions.' + )] + public function delete(int $templateId): DeletedItemResult + { + return new DeletedItemResult($this->core->call('bizproc.workflow.template.delete', [ + 'ID' => $templateId + ])); + } + + /** + * The method bizproc.workflow.template.list returns list of workflow templates, specified for a site. This method requires administrator access permissions. + * @return Workflows\Template\Result\WorkflowTemplatesResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/wirkflow_template/bizproc_workflow_template_list.php + */ + #[ApiEndpointMetadata( + 'bizproc.workflow.template.list', + 'https://training.bitrix24.com/rest_help/workflows/wirkflow_template/bizproc_workflow_template_list.php', + 'The method bizproc.workflow.template.list returns list of workflow templates, specified for a site. ' + )] + public function list( + array $select = ['ID', 'MODULE_ID', 'ENTITY', 'DOCUMENT_TYPE', 'AUTO_EXECUTE', 'NAME', 'NAME', 'TEMPLATE', 'PARAMETERS', 'VARIABLES', 'CONSTANTS', 'MODIFIED', 'IS_MODIFIED', 'USER_ID', 'SYSTEM_CODE'], + array $filter = []): Workflows\Template\Result\WorkflowTemplatesResult + { + return new Workflows\Template\Result\WorkflowTemplatesResult( + $this->core->call( + 'bizproc.workflow.template.list', + [ + 'select' => $select, + 'filter' => $filter, + ] + ) + ); + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Workflow/Request/IncomingWorkflowRequest.php b/src/Services/Workflows/Workflow/Request/IncomingWorkflowRequest.php new file mode 100644 index 00000000..06e20671 --- /dev/null +++ b/src/Services/Workflows/Workflow/Request/IncomingWorkflowRequest.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Workflow\Request; + +use Bitrix24\SDK\Application\Requests\AbstractRequest; +use Bitrix24\SDK\Services\Workflows\Common\Auth; +use Bitrix24\SDK\Services\Workflows\Common\WorkflowDocumentId; +use Bitrix24\SDK\Services\Workflows\Common\WorkflowDocumentType; +use Symfony\Component\HttpFoundation\Request; + +class IncomingWorkflowRequest extends AbstractRequest +{ + public function __construct( + Request $request, + readonly public string $workflowId, + readonly public string $code, + readonly public WorkflowDocumentId $workflowDocumentId, + readonly public WorkflowDocumentType $workflowDocumentType, + readonly public string $eventToken, + readonly public array $properties, + readonly public bool $isUseSubscription, + readonly public int $timeoutDuration, + readonly public int $timestamp, + readonly public Auth $auth + ) + { + parent::__construct($request); + } + + public static function initFromRequest(Request $request): self + { + $data = $request->request->all(); + return new self( + $request, + (string)$data['workflow_id'], + $data['code'], + WorkflowDocumentId::initFromArray($data['document_id']), + WorkflowDocumentType::initFromArray($data['document_type']), + $data['event_token'], + $data['properties'], + $data['use_subscription'] === 'Y' ? true : false, + (int)$data['timeout_duration'], + (int)$data['ts'], + Auth::initFromArray($data['auth']) + ); + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Workflow/Result/WorkflowInstanceItemResult.php b/src/Services/Workflows/Workflow/Result/WorkflowInstanceItemResult.php new file mode 100644 index 00000000..942db4a9 --- /dev/null +++ b/src/Services/Workflows/Workflow/Result/WorkflowInstanceItemResult.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Workflow\Result; + +use Bitrix24\SDK\Core\Result\AbstractItem; +use Bitrix24\SDK\Services\Workflows\Common\WorkflowAutoExecutionType; +use Carbon\CarbonImmutable; + +/** + * @property-read string $ID workflow ID + * @property-read CarbonImmutable $MODIFIED + * @property-read ?CarbonImmutable $OWNED_UNTIL time for blocking of a workflow. Process is considered as unresponsive, if the difference of blocking time with the current time is more than 5 minutes; + * @property-read ?CarbonImmutable $STARTED workflow launch date; + * @property-read ?string $MODULE_ID module ID (as per document); + * @property-read ?string $ENTITY entity ID (as per document); + * @property-read ?int $DOCUMENT_ID document ID; + * @property-read ?int $STARTED_BY who launched the workflow; + * @property-read ?int $TEMPLATE_ID workflow template ID. + */ +class WorkflowInstanceItemResult extends AbstractItem +{ + public function __get($offset) + { + switch ($offset) { + case 'STARTED_BY': + case 'TEMPLATE_ID': + return (int)$this->data[$offset]; + case 'DOCUMENT_ID': + if ($this->data[$offset] !== '') { + // "DEAL_158310" + return (int)substr((string) $this->data[$offset], strpos((string) $this->data[$offset], '_')+1); + } + return null; + case 'MODIFIED': + case 'STARTED': + if ($this->data[$offset] !== '') { + return CarbonImmutable::createFromFormat(DATE_ATOM, $this->data[$offset]); + } + return null; + } + return $this->data[$offset] ?? null; + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Workflow/Result/WorkflowInstanceStartResult.php b/src/Services/Workflows/Workflow/Result/WorkflowInstanceStartResult.php new file mode 100644 index 00000000..99c146f0 --- /dev/null +++ b/src/Services/Workflows/Workflow/Result/WorkflowInstanceStartResult.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Workflow\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class WorkflowInstanceStartResult extends AbstractResult +{ + public function getRunningWorkflowInstanceId(): string + { + return $this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Workflow/Result/WorkflowInstancesResult.php b/src/Services/Workflows/Workflow/Result/WorkflowInstancesResult.php new file mode 100644 index 00000000..45d8c647 --- /dev/null +++ b/src/Services/Workflows/Workflow/Result/WorkflowInstancesResult.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Workflow\Result; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Result\AbstractItem; +use Bitrix24\SDK\Core\Result\AbstractResult; + +class WorkflowInstancesResult extends AbstractResult +{ + /** + * @return WorkflowInstanceItemResult[] + * @throws BaseException + */ + public function getInstances(): array + { + $res = []; + foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { + $res[] = new WorkflowInstanceItemResult($item); + } + + return $res; + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Workflow/Result/WorkflowKillResult.php b/src/Services/Workflows/Workflow/Result/WorkflowKillResult.php new file mode 100644 index 00000000..1f71e8f5 --- /dev/null +++ b/src/Services/Workflows/Workflow/Result/WorkflowKillResult.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Workflow\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class WorkflowKillResult extends AbstractResult +{ + public function isSuccess(): bool + { + return $this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Workflow/Result/WorkflowTerminationResult.php b/src/Services/Workflows/Workflow/Result/WorkflowTerminationResult.php new file mode 100644 index 00000000..65405c41 --- /dev/null +++ b/src/Services/Workflows/Workflow/Result/WorkflowTerminationResult.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Workflow\Result; + +use Bitrix24\SDK\Core\Result\AbstractResult; + +class WorkflowTerminationResult extends AbstractResult +{ + public function isSuccess(): bool + { + return $this->getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Workflow/Service/Batch.php b/src/Services/Workflows/Workflow/Service/Batch.php new file mode 100644 index 00000000..d8c3df6d --- /dev/null +++ b/src/Services/Workflows/Workflow/Service/Batch.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Workflow\Service; + +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +use Psr\Log\LoggerInterface; + +readonly class Batch +{ + public function __construct( + protected BatchOperationsInterface $batch, + protected LoggerInterface $log) + { + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Workflow/Service/Workflow.php b/src/Services/Workflows/Workflow/Service/Workflow.php new file mode 100644 index 00000000..55071fc4 --- /dev/null +++ b/src/Services/Workflows/Workflow/Service/Workflow.php @@ -0,0 +1,175 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows\Workflow\Service; + +use Bitrix24\SDK\Attributes\ApiEndpointMetadata; +use Bitrix24\SDK\Attributes\ApiServiceMetadata; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\AbstractService; +use Bitrix24\SDK\Services\Workflows; +use Psr\Log\LoggerInterface; +#[ApiServiceMetadata(new Scope(['bizproc']))] +class Workflow extends AbstractService +{ + public function __construct( + public Batch $batch, + CoreInterface $core, + LoggerInterface $log + ) + { + parent::__construct($core, $log); + } + + /** + * Deletes a launched workflow + * + * @param non-empty-string $workflowId Workflow id + * @return Workflows\Workflow\Result\WorkflowKillResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/workflow/bizproc_workflow_kill.php + */ + #[ApiEndpointMetadata( + 'bizproc.workflow.kill', + 'https://training.bitrix24.com/rest_help/workflows/workflow/bizproc_workflow_kill.php', + 'Deletes a launched workflow' + )] + public function kill(string $workflowId): Workflows\Workflow\Result\WorkflowKillResult + { + return new Workflows\Workflow\Result\WorkflowKillResult($this->core->call('bizproc.workflow.kill', [ + 'ID' => $workflowId, + ])); + } + + /** + * Stops an active workflow. + * + * @return Workflows\Workflow\Result\WorkflowTerminationResult + * @see https://training.bitrix24.com/rest_help/workflows/workflow/bizproc_workflow_terminate.php + */ + #[ApiEndpointMetadata( + 'bizproc.workflow.terminate', + 'https://training.bitrix24.com/rest_help/workflows/workflow/bizproc_workflow_terminate.php', + 'Stops an active workflow.' + )] + public function terminate(string $workflowId, string $message): Workflows\Workflow\Result\WorkflowTerminationResult + { + return new Workflows\Workflow\Result\WorkflowTerminationResult($this->core->call('bizproc.workflow.terminate', [ + 'ID' => $workflowId, + 'STATUE' => $message + ])); + } + + /** + * bizproc.workflow.start launches a worfklow + * + * @throws TransportException + * @throws InvalidArgumentException + * @throws BaseException + * @see https://training.bitrix24.com/rest_help/workflows/workflow/bizproc_workflow_start.php + * + */ + #[ApiEndpointMetadata( + 'bizproc.workflow.start', + 'https://training.bitrix24.com/rest_help/workflows/workflow/bizproc_workflow_start.php', + 'Launches a workflow' + )] + public function start( + Workflows\Common\DocumentType $workflowDocumentType, + int $bizProcTemplateId, + int $entityId, + array $callParameters = [], + int $smartProcessId = null + ): Workflows\Workflow\Result\WorkflowInstanceStartResult + { + $documentId = null; + switch ($workflowDocumentType) { + case Workflows\Common\DocumentType::crmLead: + $documentId = ['crm', $workflowDocumentType->value, sprintf('LEAD_%s', $entityId)]; + break; + case Workflows\Common\DocumentType::crmCompany: + $documentId = ['crm', $workflowDocumentType->value, sprintf('COMPANY_%s', $entityId)]; + break; + case Workflows\Common\DocumentType::crmContact: + $documentId = ['crm', $workflowDocumentType->value, sprintf('CONTACT_%s', $entityId)]; + break; + case Workflows\Common\DocumentType::crmDeal: + $documentId = ['crm', $workflowDocumentType->value, sprintf('DEAL_%s', $entityId)]; + break; + case Workflows\Common\DocumentType::discBizProcDocument: + $documentId = ['disk', $workflowDocumentType->value, $entityId]; + break; + case Workflows\Common\DocumentType::listBizProcDocumentLists: + case Workflows\Common\DocumentType::listBizProcDocument: + $documentId = ['lists', $workflowDocumentType->value, $entityId]; + break; + case Workflows\Common\DocumentType::smartProcessDynamic: + if ($smartProcessId === null) { + throw new InvalidArgumentException('smartProcessId not set'); + } + $documentId = ['crm', $workflowDocumentType->value, sprintf('DYNAMIC_%s_%s', $smartProcessId, $entityId)]; + break; + case Workflows\Common\DocumentType::task: + $documentId = ['tasks', $workflowDocumentType->value, $entityId]; + break; + case Workflows\Common\DocumentType::invoice: + $documentId = ['tasks', $workflowDocumentType->value, sprintf('SMART_INVOICE_%s', $entityId)]; + break; + } + + return new Workflows\Workflow\Result\WorkflowInstanceStartResult($this->core->call( + 'bizproc.workflow.start', + [ + 'TEMPLATE_ID' => $bizProcTemplateId, + 'DOCUMENT_ID' => $documentId, + 'PARAMETERS' => $callParameters + ] + )); + + } + + /** + * returns list of launched workflows + * + * @return Workflows\Workflow\Result\WorkflowInstancesResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/workflow/bizproc_workflow_instances.php + */ + #[ApiEndpointMetadata( + 'bizproc.workflow.instances', + 'https://training.bitrix24.com/rest_help/workflows/workflow/bizproc_workflow_instances.php', + 'returns list of launched workflows' + )] + public function instances( + array $select = ['ID', 'MODIFIED', 'OWNED_UNTIL', 'MODULE_ID', 'ENTITY', 'DOCUMENT_ID', 'STARTED', 'STARTED_BY', 'TEMPLATE_ID'], + array $order = ['STARTED' => 'DESC'], + array $filter = []): Workflows\Workflow\Result\WorkflowInstancesResult + { + return new Workflows\Workflow\Result\WorkflowInstancesResult( + $this->core->call( + 'bizproc.workflow.instances', + [ + 'select' => $select, + 'order' => $order, + 'filter' => $filter, + ] + ) + ); + } +} \ No newline at end of file diff --git a/src/Services/Workflows/WorkflowsServiceBuilder.php b/src/Services/Workflows/WorkflowsServiceBuilder.php new file mode 100644 index 00000000..e7475a5e --- /dev/null +++ b/src/Services/Workflows/WorkflowsServiceBuilder.php @@ -0,0 +1,105 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Services\Workflows; + +use Bitrix24\SDK\Infrastructure\Filesystem\Base64Encoder; +use Bitrix24\SDK\Services\AbstractServiceBuilder; +use Bitrix24\SDK\Services\Workflows; +use Symfony\Component\Filesystem\Filesystem; + +class WorkflowsServiceBuilder extends AbstractServiceBuilder +{ + public function event(): Workflows\Event\Service\Event + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Workflows\Event\Service\Event( + new Workflows\Event\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + + public function robot(): Workflows\Robot\Service\Robot + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Workflows\Robot\Service\Robot( + new Workflows\Template\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + + public function activity(): Workflows\Activity\Service\Activity + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Workflows\Activity\Service\Activity( + new Workflows\Activity\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + + public function task(): Workflows\Task\Service\Task + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Workflows\Task\Service\Task( + new Workflows\Task\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + + public function template(): Workflows\Template\Service\Template + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Workflows\Template\Service\Template( + new Workflows\Template\Service\Batch($this->batch, $this->log), + $this->core, + new Base64Encoder( + new Filesystem(), + new \Symfony\Component\Mime\Encoder\Base64Encoder(), + $this->log, + ), + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } + + public function workflow(): Workflows\Workflow\Service\Workflow + { + if (!isset($this->serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Workflows\Workflow\Service\Workflow( + new Workflows\Workflow\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } +} \ No newline at end of file diff --git a/src/bitrix24.php b/src/bitrix24.php deleted file mode 100644 index 1e547d32..00000000 --- a/src/bitrix24.php +++ /dev/null @@ -1,1157 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24; - -use Bitrix24\Contracts\iBitrix24; -use Bitrix24\Exceptions\Bitrix24ApiException; -use Bitrix24\Exceptions\Bitrix24BadGatewayException; -use Bitrix24\Exceptions\Bitrix24EmptyResponseException; -use Bitrix24\Exceptions\Bitrix24Exception; -use Bitrix24\Exceptions\Bitrix24IoException; -use Bitrix24\Exceptions\Bitrix24MethodNotFoundException; -use Bitrix24\Exceptions\Bitrix24PaymentRequiredException; -use Bitrix24\Exceptions\Bitrix24PortalDeletedException; -use Bitrix24\Exceptions\Bitrix24PortalRenamedException; -use Bitrix24\Exceptions\Bitrix24SecurityException; -use Bitrix24\Exceptions\Bitrix24TokenIsExpiredException; -use Bitrix24\Exceptions\Bitrix24TokenIsInvalidException; -use Bitrix24\Exceptions\Bitrix24WrongClientException; -use Psr\Log\LoggerInterface; -use Psr\Log\NullLogger; - -/** - * Class Bitrix24 - * @author Mesilov Maxim - * @copyright 2013 - 2016 Mesilov Maxim - */ -class Bitrix24 implements iBitrix24 -{ - /** - * @var string SDK version - */ - const VERSION = '1.0'; - - /** - * @var string OAuth server - */ - const OAUTH_SERVER = 'oauth.bitrix.info'; - - - /** - * @var string access token - */ - protected $accessToken; - - /** - * @var string refresh token - */ - protected $refreshToken; - - /** - * @var string domain - */ - protected $domain; - - /** - * @var array scope - */ - protected $applicationScope = array(); - - /** - * @var string application id - */ - protected $applicationId; - - /** - * @var string application secret - */ - protected $applicationSecret; - - /** - * @var array raw request, contain all cURL options array and API query - */ - protected $rawRequest; - - /** - * @var array, contain all api-method parameters, vill be available after call method - */ - protected $methodParameters; - - /** - * @var array request info data structure акщь curl_getinfo function - */ - protected $requestInfo; - - /** - * @var bool if true raw response from bitrix24 will be available from method getRawResponse, this is debug mode - */ - protected $isSaveRawResponse = false; - - /** - * @var array raw response from bitrix24 - */ - protected $rawResponse; - - /** - * @var string redirect URI from application settings - */ - protected $redirectUri; - - /** - * @var string portal GUID - */ - protected $memberId; - - /** - * @var array custom options for cURL - */ - protected $customCurlOptions; - - /** - * @see https://github.com/Seldaek/monolog - * @var \Monolog\Logger PSR-3 compatible logger, use only from wrappers methods log* - */ - protected $log; - - /** - * @var integer CURL request count retries - */ - protected $retriesToConnectCount; - - /** - * @var integer retries to connect timeout in microseconds - */ - protected $retriesToConnectTimeout; - - /** - * @var array pending batch calls - */ - protected $_batch = array(); - - /** - * @var callable callback for expired tokens - */ - protected $_onExpiredToken; - - /** - * Create a object to work with Bitrix24 REST API service - * - * @param bool $isSaveRawResponse - if true raw response from bitrix24 will be available from method getRawResponse, this is debug mode - * @param null|LoggerInterface $obLogger - instance of \Monolog\Logger - * - * @throws Bitrix24Exception - * - * @return Bitrix24 - */ - public function __construct($isSaveRawResponse = false, LoggerInterface $obLogger = null) - { - if (!extension_loaded('curl')) { - throw new Bitrix24Exception('cURL extension must be installed to use this library'); - } - if (!is_bool($isSaveRawResponse)) { - throw new Bitrix24Exception('isSaveRawResponse flag must be boolean'); - } - $this->isSaveRawResponse = $isSaveRawResponse; - if ($obLogger !== null) { - /** - * @var \Monolog\Logger - */ - $this->log = clone $obLogger; - } else { - // dev/null logger - /** - * @var \Monolog\Logger - */ - $this->log = new NullLogger(); - } - $this->setRetriesToConnectCount(1); - $this->setRetriesToConnectTimeout(1000000); - } - - /** - * Set function called on token expiration. Callback receives instance as first parameter. - * If callback returns true, API call will be retried. - * - * @param callable $callback - */ - public function setOnExpiredToken(callable $callback) - { - $this->_onExpiredToken = $callback; - } - - /** - * Get a random string to sign protected api-call. Use salt for argument "state" in secure api-call - * random string is a result of mt_rand function - * - * @return int - */ - public function getSecuritySignSalt() - { - return mt_rand(); - } - - /** - * Set custom cURL options, overriding default ones - * - * @link http://php.net/manual/en/function.curl-setopt.php - * - * @param array $options - array(CURLOPT_XXX => value1, CURLOPT_XXX2 => value2,...) - * - * @return bool - */ - public function setCustomCurlOptions($options) - { - $this->customCurlOptions = $options; - - return true; - } - - /** - * Return additional parameters of last api-call. Data available after you try to call method call - * - * @return array | null - */ - public function getMethodParameters() - { - return $this->methodParameters; - } - - /** - * Get new access token - * - * @return array - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * @throws Bitrix24PortalRenamedException - */ - public function getNewAccessToken() - { - $applicationId = $this->getApplicationId(); - $applicationSecret = $this->getApplicationSecret(); - $refreshToken = $this->getRefreshToken(); - $applicationScope = $this->getApplicationScope(); - $redirectUri = $this->getRedirectUri(); - - if (null === $applicationId) { - throw new Bitrix24Exception('application id not found, you must call setApplicationId method before'); - } elseif (null === $applicationSecret) { - throw new Bitrix24Exception('application id not found, you must call setApplicationSecret method before'); - } elseif (null === $refreshToken) { - throw new Bitrix24Exception('application id not found, you must call setRefreshToken method before'); - } elseif (0 === count($applicationScope)) { - throw new Bitrix24Exception('application scope not found, you must call setApplicationScope method before'); - } elseif (null === $redirectUri) { - throw new Bitrix24Exception('application redirect URI not found, you must call setRedirectUri method before'); - } - -// $url = 'https://'.self::OAUTH_SERVER.'/oauth/token/'. - $url = 'https://' . $this->getDomain() . '/oauth/token/' . - '?client_id=' . urlencode($applicationId) . - '&grant_type=refresh_token' . - '&client_secret=' . $applicationSecret . - '&refresh_token=' . $refreshToken . - '&redirect_uri=' . urlencode($redirectUri); - $requestResult = $this->executeRequest($url); - // handling bitrix24 api-level errors - $this->handleBitrix24APILevelErrors($requestResult, 'refresh access token'); - return $requestResult; - } - - /** - * Get application id - * - * @return string - */ - public function getApplicationId() - { - return $this->applicationId; - } - - /** - * Set application id - * - * @param string $applicationId - * - * @throws Bitrix24Exception - * - * @return true; - */ - public function setApplicationId($applicationId) - { - if ('' === $applicationId) { - throw new Bitrix24Exception('application id is empty'); - } - $this->applicationId = $applicationId; - return true; - } - - /** - * Get application secret - * - * @return string - */ - public function getApplicationSecret() - { - return $this->applicationSecret; - } - - /** - * Set application secret - * - * @param string $applicationSecret - * - * @throws Bitrix24Exception - * - * @return true; - */ - public function setApplicationSecret($applicationSecret) - { - if ('' === $applicationSecret) { - throw new Bitrix24Exception('application secret is empty'); - } - $this->applicationSecret = $applicationSecret; - return true; - } - - /** - * Get refresh token - * - * @return string - */ - public function getRefreshToken() - { - return $this->refreshToken; - } - - /** - * Set refresh token - * - * @param $refreshToken - * - * @throws Bitrix24Exception - * - * @return true; - */ - public function setRefreshToken($refreshToken) - { - if ('' === $refreshToken) { - throw new Bitrix24Exception('refresh token is empty'); - } - $this->refreshToken = $refreshToken; - return true; - } - - /** - * Get application scope - * - * @return string - */ - public function getApplicationScope() - { - return $this->applicationScope; - } - - /** - * Set application scope - * - * @param array $applicationScope - * - * @return boolean - * - * @throws Bitrix24Exception - */ - public function setApplicationScope(array $applicationScope) - { - if (is_array($applicationScope) && count($applicationScope) > 0) { - $this->applicationScope = $applicationScope; - return true; - } else { - throw new Bitrix24Exception('application scope not set'); - } - } - - /** - * Get redirect URI - * - * @return string | null - */ - public function getRedirectUri() - { - return $this->redirectUri; - } - - /** - * Set redirect URI - * - * @param string $redirectUri - * - * @throws Bitrix24Exception - * - * @return true; - */ - public function setRedirectUri($redirectUri) - { - if ('' === $redirectUri) { - throw new Bitrix24Exception('redirect URI is empty'); - } - $this->redirectUri = $redirectUri; - return true; - }// end of SetApplicationId - - /** - * Get domain - * - * @return string | null - */ - public function getDomain() - { - return $this->domain; - } - - /** - * Set domain - * - * @param $domain - * - * @throws Bitrix24Exception - * - * @return true; - */ - public function setDomain($domain) - { - if ('' === $domain) { - throw new Bitrix24Exception('domain is empty'); - } - $this->domain = $domain; - return true; - } - - /** - * Execute a request API to Bitrix24 using cURL - * - * @param string $url - * @param array $additionalParameters - * - * @throws Bitrix24Exception - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24BadGatewayException - */ - protected function executeRequest($url, array $additionalParameters = array()) - { - $retryableErrorCodes = array( - CURLE_COULDNT_RESOLVE_HOST, - CURLE_COULDNT_CONNECT, - CURLE_HTTP_NOT_FOUND, - CURLE_READ_ERROR, - CURLE_OPERATION_TIMEOUTED, - CURLE_HTTP_POST_ERROR, - CURLE_SSL_CONNECT_ERROR - ); - - $curlOptions = array( - CURLOPT_FOLLOWLOCATION => true, - CURLOPT_RETURNTRANSFER => true, - CURLINFO_HEADER_OUT => true, - CURLOPT_VERBOSE => true, - CURLOPT_CONNECTTIMEOUT => 65, - CURLOPT_TIMEOUT => 70, - CURLOPT_USERAGENT => strtolower(__CLASS__ . '-PHP-SDK/v' . self::VERSION), - CURLOPT_POST => true, - CURLOPT_POSTFIELDS => http_build_query($additionalParameters), - CURLOPT_URL => $url - ); - - if (is_array($this->customCurlOptions)) { - foreach ($this->customCurlOptions as $customCurlOptionKey => $customCurlOptionValue) { - $curlOptions[$customCurlOptionKey] = $customCurlOptionValue; - } - } - - $this->rawRequest = $curlOptions; - $curl = curl_init(); - curl_setopt_array($curl, $curlOptions); - - $curlResult = false; - $retriesCnt = $this->retriesToConnectCount; - while ($retriesCnt--) { - $this->log->debug(sprintf('try [%s] to connect to host [%s]', $retriesCnt, $this->getDomain())); - $curlResult = curl_exec($curl); - // handling network I/O errors - if (false === $curlResult) { - $curlErrorNumber = curl_errno($curl); - $errorMsg = sprintf('in try[%s] cURL error (code %s): %s' . PHP_EOL, $retriesCnt, $curlErrorNumber, - curl_error($curl)); - if (false === in_array($curlErrorNumber, $retryableErrorCodes, true) || !$retriesCnt) { - $this->log->error($errorMsg, $this->getErrorContext()); - curl_close($curl); - throw new Bitrix24IoException($errorMsg); - } else { - $this->log->warning($errorMsg, $this->getErrorContext()); - } - usleep($this->getRetriesToConnectTimeout()); - continue; - } - $this->requestInfo = curl_getinfo($curl); - $this->rawResponse = $curlResult; - $this->log->debug('cURL request info', array($this->getRequestInfo())); - curl_close($curl); - break; - } - - // handling URI level resource errors - switch ($this->requestInfo['http_code']) { - case 403: - $errorMsg = sprintf('portal [%s] deleted, query aborted', $this->getDomain()); - $this->log->error($errorMsg, $this->getErrorContext()); - throw new Bitrix24PortalDeletedException($errorMsg); - break; - - case 502: - $errorMsg = sprintf('bad gateway to portal [%s]', $this->getDomain()); - $this->log->error($errorMsg, $this->getErrorContext()); - throw new Bitrix24BadGatewayException($errorMsg); - break; - } - - // handling server-side API errors: empty response from bitrix24 portal - if ($curlResult === '') { - $errorMsg = sprintf('empty response from portal [%s]', $this->getDomain()); - $this->log->error($errorMsg, $this->getErrorContext()); - throw new Bitrix24EmptyResponseException($errorMsg); - } - - // handling json_decode errors - $jsonResult = json_decode($curlResult, true); - unset($curlResult); - $jsonErrorCode = json_last_error(); - if (null === $jsonResult && (JSON_ERROR_NONE !== $jsonErrorCode)) { - /** - * @todo add function json_last_error_msg() - */ - $errorMsg = 'fatal error in function json_decode.' . PHP_EOL . 'Error code: ' . $jsonErrorCode . PHP_EOL; - $this->log->error($errorMsg, $this->getErrorContext()); - throw new Bitrix24Exception($errorMsg); - } - return $jsonResult; - } - - /** - * get error context - * - * @return array - */ - protected function getErrorContext() - { - return array( - // portal specific settings - 'B24_DOMAIN' => $this->getDomain(), - 'B24_MEMBER_ID' => $this->getMemberId(), - 'B24_ACCESS_TOKEN' => $this->getAccessToken(), - 'B24_REFRESH_TOKEN' => $this->getRefreshToken(), - // application settings - 'APPLICATION_SCOPE' => $this->getApplicationScope(), - 'APPLICATION_ID' => $this->getApplicationId(), - 'APPLICATION_SECRET' => $this->getApplicationSecret(), - 'REDIRECT_URI' => $this->getRedirectUri(), - // network - 'RAW_REQUEST' => $this->getRawRequest(), - 'CURL_REQUEST_INFO' => $this->getRequestInfo(), - 'RAW_RESPONSE' => $this->getRawResponse() - ); - } - - /** - * Get memeber ID - * - * @return string | null - */ - public function getMemberId() - { - return $this->memberId; - } - - /** - * Set member ID — portal GUID - * - * @param string $memberId - * - * @throws Bitrix24Exception - * - * @return true - */ - public function setMemberId($memberId) - { - if ('' === $memberId) { - throw new Bitrix24Exception('memberId is empty'); - } elseif (null === $memberId) { - throw new Bitrix24Exception('memberId is null'); - } - $this->memberId = $memberId; - return true; - } - - /** - * Get access token - * - * @return string | null - */ - public function getAccessToken() - { - return $this->accessToken; - } - - /** - * Set access token - * - * @param string $accessToken - * - * @throws Bitrix24Exception - * - * @return true - */ - public function setAccessToken($accessToken) - { - if ('' === $accessToken) { - throw new Bitrix24Exception('access token is empty'); - } - $this->accessToken = $accessToken; - return true; - } - - /** - * Return raw request, contain all cURL options array and API query. Data available after you try to call method call - * numbers of array keys is const of cURL module. Example: CURLOPT_RETURNTRANSFER = 19913 - * - * @return array | null - */ - public function getRawRequest() - { - return $this->rawRequest; - } - - /** - * Return result from function curl_getinfo. Data available after you try to call method call - * - * @return array | null - */ - public function getRequestInfo() - { - return $this->requestInfo; - } - - /** - * Get raw response from Bitrix24 before json_decode call, method available only in debug mode. - * To activate debug mode you must before set to true flag isSaveRawResponse in class construct - * - * @return string | null - */ - public function getRawResponse() - { - return $this->rawResponse; - } - - /** - * get retries to connect timeout in microseconds - * - * @return mixed - */ - public function getRetriesToConnectTimeout() - { - return $this->retriesToConnectTimeout; - } - - /** - * set retries to connect timeout in microseconds - * @param int $microseconds - * @return bool - * @throws Bitrix24Exception - */ - public function setRetriesToConnectTimeout($microseconds = 1000000) - { - $this->log->debug(sprintf('set retries to connect count %s', $microseconds)); - if (!is_numeric($microseconds)) { - throw new Bitrix24Exception('retries to connect count must be an integer'); - } - $this->retriesToConnectTimeout = $microseconds; - return true; - } - - /** - * Handling bitrix24 api-level errors - * - * @param $arRequestResult - * @param $methodName - * @param array $additionalParameters - * - * @return null - * - * @throws Bitrix24ApiException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * @throws Bitrix24PortalRenamedException - */ - protected function handleBitrix24APILevelErrors( - $arRequestResult, - $methodName, - array $additionalParameters = array() - ) - { - if (array_key_exists('error', $arRequestResult)) { - $errorMsg = sprintf('%s - %s in call [%s] for domain [%s]', - $arRequestResult['error'], - (array_key_exists('error_description', $arRequestResult) ? $arRequestResult['error_description'] : ''), - $methodName, - $this->getDomain()); - $this->log->error($errorMsg, $this->getErrorContext()); - // throw specific API-level exceptions - switch (strtoupper(trim($arRequestResult['error']))) { - case 'WRONG_CLIENT': - case 'ERROR_OAUTH': - throw new Bitrix24WrongClientException($errorMsg); - case 'ERROR_METHOD_NOT_FOUND': - throw new Bitrix24MethodNotFoundException($errorMsg); - case 'INVALID_TOKEN': - case 'INVALID_GRANT': - throw new Bitrix24TokenIsInvalidException($errorMsg); - case 'EXPIRED_TOKEN': - throw new Bitrix24TokenIsExpiredException($errorMsg); - case 'PAYMENT_REQUIRED': - throw new Bitrix24PaymentRequiredException($errorMsg); - case 'NO_AUTH_FOUND': - throw new Bitrix24PortalRenamedException($errorMsg); - default: - throw new Bitrix24ApiException($errorMsg); - } - } - return null; - } - - /** - * Authorize and get first access token - * - * @param $code - * - * @return array - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * @throws Bitrix24PortalRenamedException - */ - public function getFirstAccessToken($code) - { - $applicationId = $this->getApplicationId(); - $applicationSecret = $this->getApplicationSecret(); - $applicationScope = $this->getApplicationScope(); - $redirectUri = $this->getRedirectUri(); - - if (null === $applicationId) { - throw new Bitrix24Exception('application id not found, you must call setApplicationId method before'); - } elseif (null === $applicationSecret) { - throw new Bitrix24Exception('application id not found, you must call setApplicationSecret method before'); - } elseif (0 === count($applicationScope)) { - throw new Bitrix24Exception('application scope not found, you must call setApplicationScope method before'); - } elseif (null === $redirectUri) { - throw new Bitrix24Exception('application redirect URI not found, you must call setRedirectUri method before'); - } - -// $url = 'https://'.self::OAUTH_SERVER.'/oauth/token/'. - $url = 'https://' . $this->getDomain() . '/oauth/token/' . - '?client_id=' . urlencode($applicationId) . - '&grant_type=authorization_code' . - '&client_secret=' . $applicationSecret . - '&redirect_uri=' . urlencode($redirectUri) . - '&code=' . urlencode($code); - - $requestResult = $this->executeRequest($url); - // handling bitrix24 api-level errors - $this->handleBitrix24APILevelErrors($requestResult, 'get first access token'); - return $requestResult; - } - - /** - * Check is access token expire, call list of all available api-methods from B24 portal with current access token - * if we have an error code expired_token then return true else return false - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * @throws Bitrix24PortalRenamedException - * - * @return boolean - */ - public function isAccessTokenExpire() - { - $isTokenExpire = false; - $accessToken = $this->getAccessToken(); - $domain = $this->getDomain(); - - if (null === $domain) { - throw new Bitrix24Exception('domain not found, you must call setDomain method before'); - } elseif (null === $accessToken) { - throw new Bitrix24Exception('application id not found, you must call setAccessToken method before'); - } -// $url = 'https://'.self::OAUTH_SERVER.'/rest/app.info?auth='.$accessToken; - $url = 'https://' . $domain . '/rest/app.info?auth=' . $accessToken; - $requestResult = $this->executeRequest($url); - if (isset($requestResult['error'])) { - if (in_array($requestResult['error'], array('expired_token', 'invalid_token', 'WRONG_TOKEN'), false)) { - $isTokenExpire = true; - } else { - // handle other errors - $this->handleBitrix24APILevelErrors($requestResult, 'app.info'); - } - } - return $isTokenExpire; - }// end of isTokenExpire - - /** - * Get list of all methods available for current application - * - * @param array | null $applicationScope - * @param bool $isFull - * - * @return array - * - * @throws Bitrix24Exception - * @throws Bitrix24Exception - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24PortalRenamedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - */ - public function getAvailableMethods(array $applicationScope = array(), $isFull = false) - { - $accessToken = $this->getAccessToken(); - $domain = $this->getDomain(); - - if (null === $domain) { - throw new Bitrix24Exception('domain not found, you must call setDomain method before'); - } elseif (null === $accessToken) { - throw new Bitrix24Exception('application id not found, you must call setAccessToken method before'); - } - - $showAll = ''; - if (true === $isFull) { - $showAll = '&full=true'; - } - $scope = ''; - if (null === $applicationScope) { - $scope = '&scope'; - } elseif (count(array_unique($applicationScope)) > 0) { - $scope = '&scope=' . implode(',', array_map('urlencode', array_unique($applicationScope))); - } - $url = 'https://' . $domain . '/rest/methods.json?auth=' . $accessToken . $showAll . $scope; - return $this->executeRequest($url); - } - - /** - * get list of scope for current application from bitrix24 api - * - * @param bool $isFull - * - * @throws Bitrix24Exception - * @throws Bitrix24Exception - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24PortalRenamedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * - * @return array - */ - public function getScope($isFull = false) - { - $accessToken = $this->getAccessToken(); - $domain = $this->getDomain(); - - if (null === $domain) { - throw new Bitrix24Exception('domain not found, you must call setDomain method before'); - } elseif (null === $accessToken) { - throw new Bitrix24Exception('application id not found, you must call setAccessToken method before'); - } - $showAll = ''; - if (true === $isFull) { - $showAll = '&full=true'; - } - $url = 'https://' . $domain . '/rest/scope.json?auth=' . $accessToken . $showAll; - return $this->executeRequest($url); - } - - /** - * get CURL request count retries - * - * @return int - */ - public function getRetriesToConnectCount() - { - return $this->retriesToConnectCount; - } - - /** - * set CURL request count retries - * @param $retriesCnt - * - * @return boolean - * - * @throws Bitrix24Exception - */ - public function setRetriesToConnectCount($retriesCnt = 1) - { - $this->log->debug(sprintf('set retries to connect count %s', $retriesCnt)); - if (!is_int($retriesCnt)) { - throw new Bitrix24Exception('retries to connect count must be an integer'); - } - $this->retriesToConnectCount = (int)$retriesCnt; - return true; - } - - /** - * Add call to batch. If [[$callback]] parameter is set, it will receive call result as first parameter. - * - * @param string $method - * @param array $parameters - * @param callable|null $callback - * - * @return string Unique call ID. - */ - public function addBatchCall($method, array $parameters = array(), callable $callback = null) - { - $id = uniqid(); - $this->_batch[$id] = array( - 'method' => $method, - 'parameters' => $parameters, - 'callback' => $callback, - ); - return $id; - } - - /** - * Return true, if we have unprocessed batch calls. - * - * @return bool - */ - public function hasBatchCalls() - { - return (bool)count($this->_batch); - } - - /** - * Process batch calls. - * - * @param int $halt Halt batch on error - * @param int $delay Delay between batch calls (in msec) - * - * @throws Bitrix24Exception - * @throws Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - */ - public function processBatchCalls($halt = 0, $delay = self::BATCH_DELAY) - { - $this->log->info('Bitrix24PhpSdk.processBatchCalls.start', array('batch_query_delay' => $delay)); - $batchQueryCounter = 0; - while (count($this->_batch)) { - $batchQueryCounter++; - $slice = array_splice($this->_batch, 0, self::MAX_BATCH_CALLS); - $this->log->info('bitrix24PhpSdk.processBatchCalls.callItem', array( - 'batch_query_number' => $batchQueryCounter - )); - - $commands = array(); - foreach ($slice as $idx => $call) { - $commands[$idx] = $call['method'] . '?' . http_build_query($call['parameters']); - } - - $batchResult = $this->call('batch', array('halt' => $halt, 'cmd' => $commands)); - $results = $batchResult['result']; - foreach ($slice as $idx => $call) { - if (!isset($call['callback']) || !is_callable($call['callback'])) { - continue; - } - - call_user_func($call['callback'], array( - 'result' => isset($results['result'][$idx]) ? $results['result'][$idx] : null, - 'error' => isset($results['result_error'][$idx]) ? $results['result_error'][$idx] : null, - 'total' => isset($results['result_total'][$idx]) ? $results['result_total'][$idx] : null, - 'next' => isset($results['result_next'][$idx]) ? $results['result_next'][$idx] : null, - )); - } - if (count($this->_batch) && $delay) { - usleep($delay); - } - } - $this->log->info('bitrix24PhpSdk.processBatchCalls.finish'); - } - - /** - * Execute Bitrix24 REST API method - * - * @param string $methodName - * @param array $additionalParameters - * - * @return mixed - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PortalRenamedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws Bitrix24TokenIsExpiredException - */ - public function call($methodName, array $additionalParameters = array()) - { - try { - $result = $this->_call($methodName, $additionalParameters); - } catch (Bitrix24TokenIsExpiredException $e) { - if (!is_callable($this->_onExpiredToken)) { - throw $e; - } - - $retry = call_user_func($this->_onExpiredToken, $this); - if (!$retry) { - throw $e; - } - $result = $this->_call($methodName, $additionalParameters); - } - - return $result; - } - - /** - * Execute Bitrix24 REST API method - * - * @param string $methodName - * @param array $additionalParameters - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * @throws Bitrix24SecurityException - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * @throws Bitrix24PortalRenamedException - * - * @return array - */ - protected function _call($methodName, array $additionalParameters = array()) - { - if (null === $this->getDomain()) { - throw new Bitrix24Exception('domain not found, you must call setDomain method before'); - } - if (null === $this->getAccessToken()) { - throw new Bitrix24Exception('access token not found, you must call setAccessToken method before'); - } - if ('' === $methodName) { - throw new Bitrix24Exception('method name not found, you must set method name'); - } - - $url = 'https://' . $this->domain . '/rest/' . $methodName; - $additionalParameters['auth'] = $this->accessToken; - // save method parameters for debug - $this->methodParameters = $additionalParameters; - // is secure api-call? - $isSecureCall = false; - if (array_key_exists('state', $additionalParameters)) { - $isSecureCall = true; - } - // execute request - $this->log->info('call bitrix24 method', array( - 'BITRIX24_DOMAIN' => $this->domain, - 'METHOD_NAME' => $methodName, - 'METHOD_PARAMETERS' => $additionalParameters - )); - $requestResult = $this->executeRequest($url, $additionalParameters); - // check errors and throw exception if errors exists - $this->handleBitrix24APILevelErrors($requestResult, $methodName, $additionalParameters); - // handling security sign for secure api-call - if ($isSecureCall) { - if (array_key_exists('signature', $requestResult)) { - // check signature structure - if (strpos($requestResult['signature'], '.') === false) { - throw new Bitrix24SecurityException('security signature is corrupted'); - } - if (null === $this->getMemberId()) { - throw new Bitrix24Exception('member-id not found, you must call setMemberId method before'); - } - if (null === $this->getApplicationSecret()) { - throw new Bitrix24Exception('application secret not found, you must call setApplicationSecret method before'); - } - // prepare - $key = md5($this->getMemberId() . $this->getApplicationSecret()); - $delimiterPosition = strrpos($requestResult['signature'], '.'); - $dataToDecode = substr($requestResult['signature'], 0, $delimiterPosition); - $signature = base64_decode(substr($requestResult['signature'], $delimiterPosition + 1)); - // compare signatures - $hash = hash_hmac('sha256', $dataToDecode, $key, true); - if ($hash !== $signature) { - throw new Bitrix24SecurityException('security signatures not same, bad request'); - } - // decode - $arClearData = json_decode(base64_decode($dataToDecode), true); - // handling json_decode errors - $jsonErrorCode = json_last_error(); - if (null === $arClearData && (JSON_ERROR_NONE !== $jsonErrorCode)) { - /** - * @todo add function json_last_error_msg() - */ - $errorMsg = 'fatal error in function json_decode.' . PHP_EOL . 'Error code: ' . $jsonErrorCode . PHP_EOL; - throw new Bitrix24Exception($errorMsg); - } - // merge dirty and clear data - unset($arClearData['state']); - $requestResult ['result'] = array_merge($requestResult ['result'], $arClearData); - } else { - throw new Bitrix24SecurityException('security signature in api-response not found'); - } - } - return $requestResult; - } -} diff --git a/src/classes/access.php b/src/classes/access.php deleted file mode 100644 index 7f2676b2..00000000 --- a/src/classes/access.php +++ /dev/null @@ -1,28 +0,0 @@ -client->call( - 'access.name', - array( - 'ACCESS' => $access - ) - ); - - return $result; - } -} - diff --git a/src/classes/app/app.php b/src/classes/app/app.php deleted file mode 100644 index 1d6fb866..00000000 --- a/src/classes/app/app.php +++ /dev/null @@ -1,22 +0,0 @@ -client->call('app.info', array('state' => $this->client->getSecuritySignSalt())); - return $result; - } -} \ No newline at end of file diff --git a/src/classes/bitrix24application.php b/src/classes/bitrix24application.php deleted file mode 100644 index 70311d89..00000000 --- a/src/classes/bitrix24application.php +++ /dev/null @@ -1,39 +0,0 @@ -client = $client; - } -} \ No newline at end of file diff --git a/src/classes/bizproc/Activity.php b/src/classes/bizproc/Activity.php deleted file mode 100644 index 074b7895..00000000 --- a/src/classes/bizproc/Activity.php +++ /dev/null @@ -1,125 +0,0 @@ -client->call('bizproc.activity.add', - array( - 'CODE' => $code, - 'HANDLER' => $handler, - 'AUTH_USER_ID' => $userId, - 'USE_SUBSCRIPTION' => $subscription, - 'NAME' => $arName, - 'DESCRIPTION' => $arDescription, - 'PROPERTIES' => $arProps, - 'RETURN_PROPERTIES' => $arReturnProps, - 'DOCUMENT_TYPE' => $arDocType, - 'FILTER' => $arFilter, - )); - return $arResult['result']; - } - - - /** - * get list of installed activities - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function getList() - { - $arResult = $this->client->call('bizproc.activity.list', - array() - ); - return $arResult['result']; - } - - /** - * delete activity - * - * @param $code string - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function delete($code) - { - $arResult = $this->client->call('bizproc.activity.delete', - array( - 'code' => $code - ) - ); - return $arResult['result']; - } - -} \ No newline at end of file diff --git a/src/classes/crm/activity/activity.php b/src/classes/crm/activity/activity.php deleted file mode 100644 index f672a601..00000000 --- a/src/classes/crm/activity/activity.php +++ /dev/null @@ -1,111 +0,0 @@ -client->call( - 'crm.activity.add', - array('fields' => $fields) - ); - return $fullResult; - } - - /** - * delete activity by id - * @param integer $entityId - activity identifier - * @link http://dev.1c-bitrix.ru/rest_help/crm/rest_activity/crm_activity_delete.php - * @return array - */ - public function delete($entityId) - { - $fullResult = $this->client->call( - 'crm.activity.delete', - array('id' => $entityId) - ); - return $fullResult; - } - - /** - * get list of activity fields with description - * @link http://dev.1c-bitrix.ru/rest_help/crm/rest_activity/crm_activity_fields.php - * @return array - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.activity.fields' - ); - return $fullResult; - } - - /** - * get activity by id - * @param integer $entityId - activity identifier - * @link http://dev.1c-bitrix.ru/rest_help/crm/rest_activity/crm_activity_get.php - * @return array - */ - public function get($entityId) - { - $fullResult = $this->client->call( - 'crm.activity.get', - array('id' => $entityId) - ); - return $fullResult; - } - - /** - * Get list of activity items. - * @link http://dev.1c-bitrix.ru/rest_help/crm/rest_activity/crm_activity_list.php - * @param array $order - sort order of items - * @param array $filter - filter array - * @param array $select - array of columns to select - * @param integer $start - entity number to start from (usually returned in 'next' field of previous 'crm.activity.list' API call) - * @return array - */ - public function getList($order = array(), $filter = array(), $select = array(), $start = 0) - { - $fullResult = $this->client->call( - 'crm.activity.list', - array( - 'order' => $order, - 'filter'=> $filter, - 'select'=> $select, - 'start' => $start - ) - ); - return $fullResult; - } - - /** - * update activity by id - * @param $entityId integer - activity identifier - * @param $fields array - activity fields to update - * @link http://dev.1c-bitrix.ru/rest_help/crm/rest_activity/crm_activity_update.php - * @return array - */ - public function update($entityId, $fields) - { - $fullResult = $this->client->call( - 'crm.activity.update', - array( - 'id' => $entityId, - 'fields' => $fields - ) - ); - return $fullResult; - } - - -} - diff --git a/src/classes/crm/activity/communication.php b/src/classes/crm/activity/communication.php deleted file mode 100644 index 4b2f0430..00000000 --- a/src/classes/crm/activity/communication.php +++ /dev/null @@ -1,23 +0,0 @@ -client->call( - 'crm.activity.communication.fields' - ); - return $fullResult; - } - -} - diff --git a/src/classes/crm/additional/duplicate.php b/src/classes/crm/additional/duplicate.php deleted file mode 100644 index 96f41b74..00000000 --- a/src/classes/crm/additional/duplicate.php +++ /dev/null @@ -1,31 +0,0 @@ -client->call('crm.duplicate.findbycomm', - array( - 'type' => $communicationType, - 'values'=> $arValues, - 'entity_type'=> $entityType, - ) - ); - return $result; - } -} \ No newline at end of file diff --git a/src/classes/crm/company/company.php b/src/classes/crm/company/company.php deleted file mode 100644 index 33dda014..00000000 --- a/src/classes/crm/company/company.php +++ /dev/null @@ -1,117 +0,0 @@ -client->call( - 'crm.company.list', - array( - 'order' => $order, - 'filter'=> $filter, - 'select'=> $select, - 'start' => $start - ) - ); - return $fullResult; - } - - /** - * Add a new company to CRM - * @param array $fields array of fields - * @link http://www.bitrixsoft.com/rest_help/crm/company/crm_company_add.php - * @return array - * @throws Bitrix24Exception - * - */ - public function add($fields = array()) - { - $fullResult = $this->client->call( - 'crm.company.add', - array('fields' => $fields) - ); - return $fullResult; - } - - /** - * Updates the specified (existing) company. - * @param array $bitrix24CompanyId integer - * @param array $fields array of fields - * @link http://www.bitrixsoft.com/rest_help/crm/company/crm_company_add.php - * @return array - * @throws Bitrix24Exception - * - */ - public function update($bitrix24CompanyId, $fields = array()) - { - $fullResult = $this->client->call( - 'crm.company.update', - array('id' => $bitrix24CompanyId), - array('fields' => $fields) - ); - return $fullResult; - } - - /** - * Returns a company associated with the specified company ID. - * @link http://www.bitrixsoft.com/rest_help/crm/company/crm_company_get.php - * @param integer $bitrix24CompanyId company identifier - * @return array - * @throws Bitrix24Exception - */ - public function get($bitrix24CompanyId) - { - $fullResult = $this->client->call( - 'crm.company.get', - array('id' => $bitrix24CompanyId) - ); - return $fullResult; - } - - /** - * Deletes the specified company and all the associated objects. - * @link http://www.bitrixsoft.com/rest_help/crm/company/crm_company_delete.php - * @param integer $bitrix24CompanyId company identifier - * @return array - * @throws Bitrix24Exception - */ - public function delete($bitrix24CompanyId) - { - $fullResult = $this->client->call( - 'crm.company.delete', - array('id' => $bitrix24CompanyId) - ); - return $fullResult; - } - - /** - * Returns the description of the fields available to company. - * @link http://www.bitrixsoft.com/rest_help/crm/company/crm_company_fields.php - * @return array - * @throws Bitrix24Exception - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.company.fields' - ); - return $fullResult; - } -} diff --git a/src/classes/crm/contact/contact.php b/src/classes/crm/contact/contact.php deleted file mode 100644 index ded8e1d3..00000000 --- a/src/classes/crm/contact/contact.php +++ /dev/null @@ -1,119 +0,0 @@ -client->call( - 'crm.contact.list', - array( - 'order' => $order, - 'filter'=> $filter, - 'select'=> $select, - 'start' => $start - ) - ); - return $fullResult; - } - - /** - * Add a new contact to CRM - * @param array $fields array of fields - * @param array $params array of params - * @link http://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_add.php - * @return array - */ - public function add($fields = array(), $params = array()) - { - $fullResult = $this->client->call( - 'crm.contact.add', - array( - 'fields' => $fields, - 'params' => $params - ) - ); - return $fullResult; - } - - /** - * Get contact by identifier - * @link http://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_get.php - * @param integer $bitrix24UserId contact identifier - * @return array - * @throws Bitrix24Exception - */ - public function get($bitrix24UserId) - { - $fullResult = $this->client->call( - 'crm.contact.get', - array('id' => $bitrix24UserId) - ); - return $fullResult; - } - - /** - * Deletes the specified contact - * @link http://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_delete.php - * @param integer $bitrix24UserId contact identifier - * @return array - * @throws Bitrix24Exception - */ - public function delete($bitrix24UserId) - { - $fullResult = $this->client->call( - 'crm.contact.delete', - array('id' => $bitrix24UserId) - ); - return $fullResult; - } - - /** - * get list of contact fields with description - * @link http://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_fields.php - * @return array - * @throws Bitrix24Exception - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.contact.fields' - ); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_update.php - * @param integer $contactId Specifies the contact ID - * @param array $fields An array in format array("field"=>"value"[, ...]) containing values for the fields that need to be updated. - * The fields can be one or more of those returned by crm.contact.fields. - * @param array $params Set of parameters. REGISTER_SONET_EVENT - performs registration of a change event in a contact in the Activity Stream. - * The contact's Responsible person will also receive notification. - * @return array - */ - public function update($contactId, $fields = array(), $params = array()) - { - $fullResult = $this->client->call( - 'crm.contact.update', - array( - 'id' => $contactId, - 'fields' => $fields, - 'params' => $params - ) - ); - return $fullResult; - } -} diff --git a/src/classes/crm/contact/userfield.php b/src/classes/crm/contact/userfield.php deleted file mode 100644 index 88803309..00000000 --- a/src/classes/crm/contact/userfield.php +++ /dev/null @@ -1,97 +0,0 @@ -client->call( - 'crm.contact.userfield.list', - array( - 'order' => $order, - 'filter'=> $filter - ) - ); - return $fullResult; - } - - /** - * Get item userfield - * @link http://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_userfield_get.php - * @param integer $userfieldId - contact userfield id - * @return array - */ - public function get($userfieldId) - { - $fullResult = $this->client->call( - 'crm.contact.userfield.get', - array('id' => $userfieldId) - ); - return $fullResult; - } - - /** - * Delete userfield - * @link http://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_userfield_delete.php - * @param integer $userfieldId - contact userfield id - * @return array - */ - public function delete($userfieldId) - { - $fullResult = $this->client->call( - 'crm.contact.userfield.delete', - array('id' => $userfieldId) - ); - return $fullResult; - } - - /** - * Add a new userfield to contact - * @param array $fields array of fields - * @link http://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_userfield_add.php - * @return array - */ - public function add($fields = array()) - { - $fullResult = $this->client->call( - 'crm.contact.userfield.add', - array('fields' => $fields) - ); - return $fullResult; - } - - - /** - * Updates userfield - * - * @param $id - * @param array $fields - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/contacts/crm_contact_userfield_update.php - * @return array - */ - public function update($id, $fields = array()) - { - $fullResult = $this->client->call( - 'crm.contact.userfield.update', - array( - 'id' => $id, - 'fields' => $fields - ) - ); - - return $fullResult; - } -} diff --git a/src/classes/crm/deal/deal.php b/src/classes/crm/deal/deal.php deleted file mode 100644 index 96de0c3c..00000000 --- a/src/classes/crm/deal/deal.php +++ /dev/null @@ -1,117 +0,0 @@ -client->call( - 'crm.deal.add', - array( - 'fields' => $fields, - 'params' => $params - ) - ); - return $fullResult; - } - - /** - * delete deal by id - * @var $dealId integer deal identifier - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_delete.php - * @return array - */ - public function delete($dealId) - { - $fullResult = $this->client->call( - 'crm.deal.delete', - array('id' => $dealId) - ); - return $fullResult; - } - - /** - * get list of deal fields with description - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_fields.php - * @return array - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.deal.fields' - ); - return $fullResult; - } - - /** - * get deal by id - * @var $dealId integer deal identifier - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_get.php - * @return array - */ - public function get($dealId) - { - $fullResult = $this->client->call( - 'crm.deal.get', - array('id' => $dealId) - ); - return $fullResult; - } - - /** - * Get list of deal items. - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_list.php - * @param array $order - order of deal items - * @param array $filter - filter array - * @param array $select - array of collumns to select - * @param integer $start - entity number to start from (usually returned in 'next' field of previous 'crm.deal.list' API call) - * @return array - */ - public function getList($order = array(), $filter = array(), $select = array(), $start = 0) - { - $fullResult = $this->client->call( - 'crm.deal.list', - array( - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'start' => $start - ) - ); - return $fullResult; - } - - /** - * update deal by id - * @param integer $dealId integer deal identifier - * @param array $dealFields array deal fields to update - * @param array $params Set of parameters. REGISTER_SONET_EVENT - performs registration of a change event in a deal in the Activity Stream. - * The deals's Responsible person will also receive notification. - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_update.php - * @return array - */ - public function update($dealId, $dealFields, $params = array()) - { - $fullResult = $this->client->call( - 'crm.deal.update', - array( - 'id' => $dealId, - 'fields' => $dealFields, - 'params' => $params - ) - ); - return $fullResult; - } - - -} diff --git a/src/classes/crm/deal/productrows.php b/src/classes/crm/deal/productrows.php deleted file mode 100644 index af35edf3..00000000 --- a/src/classes/crm/deal/productrows.php +++ /dev/null @@ -1,46 +0,0 @@ -client->call( - 'crm.deal.productrows.get', - array( - 'id' => $id - ) - ); - return $fullResult; - } - - /** - * Set deal products. - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_productrows_set.php - * @param int $id - deal id - * @param array $rows - products data - * @return array - */ - public function set($id, $rows) - { - $fullResult = $this->client->call( - 'crm.deal.productrows.set', - array( - 'id' => $id, - 'rows' => $rows - ) - ); - return $fullResult; - } -} diff --git a/src/classes/crm/deal/userfield.php b/src/classes/crm/deal/userfield.php deleted file mode 100644 index eb6ecc11..00000000 --- a/src/classes/crm/deal/userfield.php +++ /dev/null @@ -1,112 +0,0 @@ -client->call( - 'crm.deal.userfield.list', - array( - 'order' => $order, - 'filter' => $filter, - ) - ); - - return $fullResult; - } - - /** - * Get item userfield - * - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_userfield_get.php - * - * @param integer $userfieldId - deal userfield id - * - * @return array - */ - public function get($userfieldId) - { - $fullResult = $this->client->call( - 'crm.deal.userfield.get', - array('id' => $userfieldId) - ); - - return $fullResult; - } - - /** - * Delete userfield - * - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_userfield_delete.php - * - * @param integer $userfieldId - deal userfield id - * - * @return array - */ - public function delete($userfieldId) - { - $fullResult = $this->client->call( - 'crm.deal.userfield.delete', - array('id' => $userfieldId) - ); - - return $fullResult; - } - - /** - * Add a new userfield to deal - * - * @param array $fields array of fields - * - * @link http://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_userfield_add.php - * @return array - */ - public function add($fields = array()) - { - $fullResult = $this->client->call( - 'crm.deal.userfield.add', - array('fields' => $fields) - ); - - return $fullResult; - } - - /** - * Add a new userfield to deal - * - * @param int $userfieldId deal userfield id - * @param array $fields array of fields - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/cdeals/crm_deal_userfield_update.php - * @return array - */ - public function update($userfieldId, $fields = array()) - { - $fullResult = $this->client->call( - 'crm.deal.userfield.update', - array( - 'id' => $userfieldId, - 'fields' => $fields, - ) - ); - - return $fullResult; - } -} \ No newline at end of file diff --git a/src/classes/crm/enum/enum.php b/src/classes/crm/enum/enum.php deleted file mode 100644 index 40638697..00000000 --- a/src/classes/crm/enum/enum.php +++ /dev/null @@ -1,109 +0,0 @@ -client->call( - 'crm.enum.fields' - ); - return $fullResult; - } - - - - /** - * get list of enum owner types - * @link http://dev.1c-bitrix.ru/rest_help/crm/auxiliary/enum/crm_enum_ownertype.php - * @return array - */ - public function ownerType() - { - $fullResult = $this->client->call( - 'crm.enum.ownertype' - ); - return $fullResult; - } - - /** - * get list of enum activity types - * @link http://dev.1c-bitrix.ru/rest_help/crm/auxiliary/enum/crm_enum_activitytype.php - * @return array - */ - public function activityType() - { - $fullResult = $this->client->call( - 'crm.enum.activitytype' - ); - return $fullResult; - } - - - /** - * get list of enum activity priorities - * @link http://dev.1c-bitrix.ru/rest_help/crm/auxiliary/enum/crm_enum_activitypriority.php - * @return array - */ - public function activityPriority() - { - $fullResult = $this->client->call( - 'crm.enum.activitypriority' - ); - return $fullResult; - } - - - /** - * get list of enum content types - * @link http://dev.1c-bitrix.ru/rest_help/crm/auxiliary/enum/crm_enum_contenttype.php - * @return array - */ - public function contentType() - { - $fullResult = $this->client->call( - 'crm.enum.contenttype' - ); - return $fullResult; - } - - - /** - * get list of enum activity directions - * @link http://dev.1c-bitrix.ru/rest_help/crm/auxiliary/enum/crm_enum-activitydirection.php - * @return array - */ - public function activityDirection() - { - $fullResult = $this->client->call( - 'crm.enum.activitydirection' - ); - return $fullResult; - } - - - /** - * get list of enum activity notify types - * @link http://dev.1c-bitrix.ru/rest_help/crm/auxiliary/enum/crm_enumactivitynotifytype.php - * @return array - */ - public function activityNotifyType() - { - $fullResult = $this->client->call( - 'crm.enum.activitynotifytype' - ); - return $fullResult; - } - - -} - - diff --git a/src/classes/crm/invoice/invoice.php b/src/classes/crm/invoice/invoice.php deleted file mode 100644 index 8266cb7a..00000000 --- a/src/classes/crm/invoice/invoice.php +++ /dev/null @@ -1,119 +0,0 @@ -client->call( - 'crm.invoice.list', - array( - 'order' => $order, - 'filter'=> $filter, - 'select'=> $select, - 'start' => $start - ) - ); - return $fullResult; - } - - /** - * get invoice by id - * @var $invoiceId integer invoice identifier - * @link http://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_get.php - * @return array - */ - public function get($invoiceId) - { - $fullResult = $this->client->call( - 'crm.invoice.get', - array('id' => $invoiceId) - ); - return $fullResult; - } - - /** - * delete invoice by id - * @var $invoiceId integer invoice identifier - * @link http://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_delete.php - * @return array - */ - public function delete($invoiceId) - { - $fullResult = $this->client->call( - 'crm.invoice.delete', - array('id' => $invoiceId) - ); - return $fullResult; - } - - /** - * Add a new invoice to CRM - * @param array $fields array of fields - * @link http://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_add.php - * @return array - */ - public function add($fields = array()) - { - $fullResult = $this->client->call( - 'crm.invoice.add', - array('fields' => $fields) - ); - return $fullResult; - } - - /** - * update invoice by id - * @var $invoiceId integer invoice identifier - * @var $invoiceFields array invoice fields to update - * @link http://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_update.php - * @return array - */ - public function update($invoiceId, $invoiceFields) - { - $fullResult = $this->client->call( - 'crm.invoice.update', - array( - 'id' => $invoiceId, - 'fields' => $invoiceFields - ) - ); - return $fullResult; - } - - /** - * get list of invoice fields with description - * @link http://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_fields.php - * @return array - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.invoice.fields' - ); - return $fullResult; - } -} diff --git a/src/classes/crm/invoice/status.php b/src/classes/crm/invoice/status.php deleted file mode 100644 index 7cf4db20..00000000 --- a/src/classes/crm/invoice/status.php +++ /dev/null @@ -1,46 +0,0 @@ -client->call( - 'crm.invoice.status.list', - array( - 'order' => $order, - 'filter'=> $filter, - 'select'=> $select, - 'start' => $start - ) - ); - return $fullResult; - } - - /** - * get by id - * @link http://dev.1c-bitrix.ru/rest_help/crm/invoice/crm_invoice_status_get.php - * @param integer $invoiceStatusId - invoice status identifier - * @return array - */ - public function get($invoiceStatusId) - { - $fullResult = $this->client->call( - 'crm.invoice.status.get', - array('id' => $invoiceStatusId) - ); - return $fullResult; - } - -} - diff --git a/src/classes/crm/lead/lead.php b/src/classes/crm/lead/lead.php deleted file mode 100644 index b2d63009..00000000 --- a/src/classes/crm/lead/lead.php +++ /dev/null @@ -1,113 +0,0 @@ -client->call( - 'crm.lead.get', - array('id' => $leadId) - ); - return $fullResult; - } - - /** - * Get list of lead items. - * @link http://dev.1c-bitrix.ru/rest_help/crm/leads/crm_lead_list.php - * @param array $order - order of task items - * @param array $filter - filter array - * @param array $select - array of collumns to select - * @param integer $start - entity number to start from (usually returned in 'next' field of previous 'crm.lead.list' API call) - * @return array - */ - public function getList($order = array(), $filter = array(), $select = array(), $start = 0) - { - $fullResult = $this->client->call( - 'crm.lead.list', - array( - 'order' => $order, - 'filter'=> $filter, - 'select'=> $select, - 'start' => $start - ) - ); - return $fullResult; - } - - /** - * Add a new lead to CRM - * @param array $fields array of fields - * @param array $params Set of parameters. REGISTER_SONET_EVENT - performs registration of a change event in a lead in the Activity Stream. - * The lead's Responsible person will also receive notification. - * @link http://dev.1c-bitrix.ru/rest_help/crm/leads/crm_lead_add.php - * @return array - */ - public function add($fields = array(), $params = array()) - { - $fullResult = $this->client->call( - 'crm.lead.add', - array( - 'fields' => $fields, - 'params' => $params - ) - ); - return $fullResult; - } - - /** - * get list of lead fields with description - * @link http://dev.1c-bitrix.ru/rest_help/crm/leads/crm_lead_fields.php - * @return array - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.lead.fields' - ); - return $fullResult; - } - - /** - * @link https://training.bitrix24.com/rest_help/crm/leads/crm_lead_update.php - * @param integer $leadId Specifies the lead ID - * @param array $fields An array in format array("field"=>"value"[, ...]) containing values for the fields that need to be updated. - * The fields can be one or more of those returned by crm.lead.fields. - * @param array $params Set of parameters. REGISTER_SONET_EVENT - performs registration of a change event in a lead in the Activity Stream. - * The lead's Responsible person will also receive notification. - * @return array - */ - public function update($leadId, $fields = array(), $params = array()) - { - $fullResult = $this->client->call( - 'crm.lead.update', - array( - 'id' => $leadId, - 'fields' => $fields, - 'params' => $params - ) - ); - return $fullResult; - } - - /** - * Deletes the specified lead and all the associated objects. - * @param integer $leadId - * @return array - */ - public function delete($leadId) - { - $fullResult = $this->client->call( - 'crm.lead.delete', - array('id' => $leadId) - ); - return $fullResult; - } -} diff --git a/src/classes/crm/lead/userfield.php b/src/classes/crm/lead/userfield.php deleted file mode 100644 index 60eab52e..00000000 --- a/src/classes/crm/lead/userfield.php +++ /dev/null @@ -1,108 +0,0 @@ -client->call( - 'crm.lead.userfield.list', - array( - 'order' => $order, - 'filter'=> $filter - ) - ); - return $fullResult; - } - - /** - * Get item userfield - * @link http://dev.1c-bitrix.ru/rest_help/crm/leads/crm_lead_userfield_get.php - * @param integer $userfieldId - lead userfield id - * @return array - */ - public function get($userfieldId) - { - $fullResult = $this->client->call( - 'crm.lead.userfield.get', - array('id' => $userfieldId) - ); - return $fullResult; - } - - /** - * delete userfield - * @link http://dev.1c-bitrix.ru/rest_help/crm/leads/crm_lead_userfield_delete.php - * @param integer $userfieldId - lead userfield id - * @return array - */ - public function delete($userfieldId) - { - $fullResult = $this->client->call( - 'crm.lead.userfield.delete', - array('id' => $userfieldId) - ); - return $fullResult; - } - - /** - * get list of lead userfield fields with description - * @link http://dev.1c-bitrix.ru/rest_help/crm/leads/crm_lead_userfield_fields.php - * @return array - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.userfield.fields' - ); - return $fullResult; - } - - /** - * Add a new userfield to lead - * @param array $fields array of fields - * @link http://dev.1c-bitrix.ru/rest_help/crm/leads/crm_lead_userfield_add.php - * @return array - */ - public function add($fields = array()) - { - $fullResult = $this->client->call( - 'crm.lead.userfield.add', - array('fields' => $fields) - ); - return $fullResult; - } - - /** - * Updates userfield - * - * @param $id - * @param array $fields - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/leads/crm_lead_userfield_update.php - * @return array - */ - public function update($id, $fields = array()) - { - $fullResult = $this->client->call( - 'crm.lead.userfield.update', - array( - 'id' => $id, - 'fields' => $fields - ) - ); - - return $fullResult; - } -} \ No newline at end of file diff --git a/src/classes/crm/livefeedmessage/livefeedmessage.php b/src/classes/crm/livefeedmessage/livefeedmessage.php deleted file mode 100644 index fe8e6bff..00000000 --- a/src/classes/crm/livefeedmessage/livefeedmessage.php +++ /dev/null @@ -1,35 +0,0 @@ -client->call( - 'crm.livefeedmessage.add', - array('fields' => array( - "POST_TITLE" => $postTitle, - "MESSAGE" => $message, - "SPERM" => $sperm, - "ENTITYTYPEID" => $entityTypeId, - "ENTITYID" => $entityId - )) - ); - return $fullResult; - } -} \ No newline at end of file diff --git a/src/classes/crm/product/product.php b/src/classes/crm/product/product.php deleted file mode 100644 index d3e75852..00000000 --- a/src/classes/crm/product/product.php +++ /dev/null @@ -1,123 +0,0 @@ -client->call( - 'crm.product.list', - array( - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'start' => $start, - ) - ); - - return $fullResult; - } - - /** - * get list of product fields with description - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_fields.php - * - * @return array - */ - public function fields() - { - return $this->client->call( - 'crm.product.fields' - ); - } - - /** - * get product by id - * - * @link http://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_get.php - * - * @param integer $productId - product item identifier - * - * @return array - */ - public function get($productId) - { - $fullResult = $this->client->call( - 'crm.product.get', - array('id' => $productId) - ); - - return $fullResult; - } - - /** - * delete product by id - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_delete.php - * - * @param integer $productId - product item identifier - * - * @return array - */ - public function delete($productId) - { - $fullResult = $this->client->call( - 'crm.product.delete', - array('id' => $productId) - ); - - return $fullResult; - } - - /** - * @param $productId - * @param array $arFields - * - * @return array - */ - public function update($productId, array $arFields) - { - return $this->client->call('crm.product.update', array( - 'id' => $productId, - 'fields' => $arFields, - )); - } - - /** - * add new product - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_add.php - * - * @param $arNewProduct - * - * @return array - */ - public function add($arNewProduct) - { - $fullResult = $this->client->call( - 'crm.product.add', - array('fields' => $arNewProduct) - ); - - return $fullResult; - } -} - - diff --git a/src/classes/crm/product/property.php b/src/classes/crm/product/property.php deleted file mode 100644 index ea939457..00000000 --- a/src/classes/crm/product/property.php +++ /dev/null @@ -1,136 +0,0 @@ -client->call( - 'crm.product.property.get', - array('id' => $productPropertyId) - ); - - return $fullResult; - } - - /** - * delete product property by id - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_property_delete.php - * - * @param integer $productPropertyId - product property identifier - * - * @return array - * @throws Bitrix24Exception - */ - public function delete($productPropertyId) - { - $fullResult = $this->client->call( - 'crm.product.property.delete', - array('id' => $productPropertyId) - ); - - return $fullResult; - } - - /** - * get product property list - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_property_list.php - * - * @param array $order - * @param array $filter - * - * @return array - * @throws Bitrix24Exception - */ - public function getList($order = array(), $filter = array()) - { - $fullResult = $this->client->call( - 'crm.product.property.list', - array( - 'order' => $order, - 'filter' => $filter, - ) - ); - - return $fullResult; - } - - /** - * add product property - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_property_list.php - * - * @param array $fields - * - * @return array - * @throws Bitrix24Exception - */ - public function add(array $fields) - { - $fullResult = $this->client->call( - 'crm.product.property.add', - array( - 'fields' => $fields, - ) - ); - - return $fullResult; - } - - /** - * update product property - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_property_update.php - * - * @param int $productPropertyId - * @param array $fields - * - * @return array - * @throws Bitrix24Exception - */ - public function update($productPropertyId, array $fields) - { - $fullResult = $this->client->call( - 'crm.product.property.add', - array( - 'id' => $productPropertyId, - 'fields' => $fields, - ) - ); - - return $fullResult; - } - - /** - * get property types - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/products/crm_product_property_types.php - * @return array - * @throws Bitrix24Exception - */ - public function getTypes() - { - return $this->client->call('crm.product.property.types'); - } -} \ No newline at end of file diff --git a/src/classes/crm/productrow/productrow.php b/src/classes/crm/productrow/productrow.php deleted file mode 100644 index e22111f1..00000000 --- a/src/classes/crm/productrow/productrow.php +++ /dev/null @@ -1,49 +0,0 @@ -client->call( - 'crm.productrow.list', - array( - 'order' => array(), - 'filter'=> array( - 'OWNER_TYPE'=> $ownerType, - 'OWNER_ID'=> $ownerId, - ), - 'select'=> array(), - 'start' => $start - ) - ); - return $fullResult; - } - - - /** - * get fields descriptions - * @link http://dev.1c-bitrix.ru/rest_help/crm/productrow/crm_productrow_fields.php - * @return array - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.productrow.fields', - array() - ); - return $fullResult; - } - -} - - diff --git a/src/classes/crm/quote/quote.php b/src/classes/crm/quote/quote.php deleted file mode 100644 index 2cdaa682..00000000 --- a/src/classes/crm/quote/quote.php +++ /dev/null @@ -1,106 +0,0 @@ -client->call( - 'crm.quote.list', - array( - 'order' => $order, - 'filter'=> $filter, - 'select'=> $select, - 'start' => $start - ) - ); - return $fullResult; - } - - /** - * get quote by id - * @var $quoteId integer quote identifier - * @link http://dev.1c-bitrix.ru/rest_help/crm/quote/crm_quote_get.php - * @return array - */ - public function get($quoteId) - { - $fullResult = $this->client->call( - 'crm.quote.get', - array('id' => $quoteId) - ); - return $fullResult; - } - - /** - * delete quote by id - * @var $quoteId integer quote identifier - * @link http://dev.1c-bitrix.ru/rest_help/crm/quote/crm_quote_delete.php - * @return array - */ - public function delete($quoteId) - { - $fullResult = $this->client->call( - 'crm.quote.delete', - array('id' => $quoteId) - ); - return $fullResult; - } - - /** - * Add a new quote to CRM - * @param array $fields array of fields - * @link http://dev.1c-bitrix.ru/rest_help/crm/quote/crm_quote_add.php - * @return array - */ - public function add($fields = array()) - { - $fullResult = $this->client->call( - 'crm.quote.add', - array('fields' => $fields) - ); - return $fullResult; - } - - /** - * update quote by id - * @var $quoteId integer quote identifier - * @var $quoteFields array quote fields to update - * @link http://dev.1c-bitrix.ru/rest_help/crm/quote/crm_quote_update.php - * @return array - */ - public function update($quoteId, $quoteFields) - { - $fullResult = $this->client->call( - 'crm.quote.update', - array( - 'id' => $quoteId, - 'fields' => $quoteFields - ) - ); - return $fullResult; - } - - /** - * get list of quote fields with description - * @link http://dev.1c-bitrix.ru/rest_help/crm/quote/crm_quote_fields.php - * @return array - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.quote.fields' - ); - return $fullResult; - } -} diff --git a/src/classes/crm/requisite/address.php b/src/classes/crm/requisite/address.php deleted file mode 100644 index 34b4a1ae..00000000 --- a/src/classes/crm/requisite/address.php +++ /dev/null @@ -1,131 +0,0 @@ -client->call( - 'crm.address.add', - array( - 'fields' => $fields, - ) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_address_delete.php - * - * @param array $fields array of fields - * - * @return array - * @throws Bitrix24Exception - */ - public function delete($fields) - { - $fullResult = $this->client->call( - 'crm.address.delete', - array('fields' => $fields) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_address_fields.php - * @return array - * @throws Bitrix24Exception - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.address.fields' - ); - return $fullResult; - } - - - /** - * Get list of requisite items. - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_address_list.php - * - * @param array $order - order of items - * @param array $filter - filter array - * @param array $select - array of collumns to select - * @param integer $start - entity number to start from (usually returned in 'next' field of previous - * 'crm.contact.list' API call) - * - * @return array - * @throws Bitrix24Exception - * - */ - public function getList($order = array(), $filter = array(), $select = array(), $start = 0) - { - $fullResult = $this->client->call( - 'crm.address.list', - array( - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'start' => $start - ) - ); - return $fullResult; - } - - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_address_update.php - * - * @param array $fields An array in format array("field"=>"value"[, ...]) containing values for the fields - * that need to be updated. The fields can be one or more of those returned by - * crm.contact.fields. - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function update($fields = array()) - { - $fullResult = $this->client->call( - 'crm.address.update', - array( - 'fields' => $fields - ) - ); - return $fullResult; - } -} diff --git a/src/classes/crm/requisite/bank.php b/src/classes/crm/requisite/bank.php deleted file mode 100644 index 2033658a..00000000 --- a/src/classes/crm/requisite/bank.php +++ /dev/null @@ -1,148 +0,0 @@ -client->call( - 'crm.requisite.bankdetail.add', - array( - 'fields' => $fields, - ) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_bankdetail_delete.php - * - * @param integer $id of bank requisite - * - * @return array - * @throws Bitrix24Exception - */ - public function delete($id) - { - $fullResult = $this->client->call( - 'crm.requisite.bankdetail.delete', - array('id' => $id) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_bankdetail_fields.php - * @return array - * @throws Bitrix24Exception - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.requisite.bankdetail.fields' - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_bankdetail_get.php - * - * @param integer $id of bank requisite - * - * @return array - * @throws Bitrix24Exception - */ - public function get($id) - { - $fullResult = $this->client->call( - 'crm.requisite.bankdetail.get', - array('id' => $id) - ); - return $fullResult; - } - - - /** - * Get list of requisite items. - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_bankdetail_list.php - * - * @param array $order - order of items - * @param array $filter - filter array - * @param array $select - array of collumns to select - * @param integer $start - entity number to start from (usually returned in 'next' field of previous - * 'crm.contact.list' API call) - * - * @return array - * @throws Bitrix24Exception - * - */ - public function getList($order = array(), $filter = array(), $select = array(), $start = 0) - { - $fullResult = $this->client->call( - 'crm.requisite.bankdetail.list', - array( - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'start' => $start - ) - ); - return $fullResult; - } - - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_bankdetail_update.php - * - * @param integer $id - * @param array $fields An array in format array("field"=>"value"[, ...]) containing values for the fields that - * need to be updated. The fields can be one or more of those returned by - * crm.requisite.bankdetail.fields - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function update($id, $fields = array()) - { - $fullResult = $this->client->call( - 'crm.requisite.bankdetail.update', - array( - 'id' => $id, - 'fields' => $fields, - ) - ); - return $fullResult; - } -} diff --git a/src/classes/crm/requisite/link.php b/src/classes/crm/requisite/link.php deleted file mode 100644 index 1663a69d..00000000 --- a/src/classes/crm/requisite/link.php +++ /dev/null @@ -1,143 +0,0 @@ -client->call( - 'crm.requisite.link.fields' - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_link_fields.php - * - * @param $entityTypeId (@see https://dev.1c-bitrix.ru/rest_help/crm/auxiliary/enum/crm_enum_ownertype.php) - * @param $entityId - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function get($entityTypeId, $entityId) - { - $fullResult = $this->client->call( - 'crm.requisite.link.get', - array( - 'entityTypeId' => $entityTypeId, - 'entityId' => $entityId, - ) - ); - return $fullResult; - } - - /** - * Get list of requisite items. - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_link_list.php - * - * @param array $order - order of items - * @param array $filter - filter array - * @param integer $start - entity number to start from (usually returned in 'next' field of previous - * 'crm.contact.list' API call) - * - * @return array - * @throws Bitrix24Exception - * - */ - public function getList($order = array(), $filter = array(), $start = 0) - { - $fullResult = $this->client->call( - 'crm.requisite.link.list', - array( - 'order' => $order, - 'filter' => $filter, - 'start' => $start - ) - ); - return $fullResult; - } - - - /** - * Get list of requisite items. - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_link_register.php - * - * @param $fields - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function register($fields) - { - $fullResult = $this->client->call( - 'crm.requisite.link.register', - array( - 'fields' => $fields, - ) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_link_unregister.php - * - * @param $entityTypeId (@see https://dev.1c-bitrix.ru/rest_help/crm/auxiliary/enum/crm_enum_ownertype.php) - * @param $entityId - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function unregister($entityTypeId, $entityId) - { - $fullResult = $this->client->call( - 'crm.requisite.link.get', - array( - 'entityTypeId' => $entityTypeId, - 'entityId' => $entityId, - ) - ); - return $fullResult; - } -} diff --git a/src/classes/crm/requisite/preset.php b/src/classes/crm/requisite/preset.php deleted file mode 100644 index 18f4cf23..00000000 --- a/src/classes/crm/requisite/preset.php +++ /dev/null @@ -1,207 +0,0 @@ -client->call( - 'crm.requisite.preset.add', - array( - 'fields' => $fields, - ) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_countries.php - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function countries() - { - $fullResult = $this->client->call( - 'crm.requisite.preset.countries' - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_delete.php - * - * @param $id - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @internal param array $fields array of fields - * - */ - public function delete($id) - { - $fullResult = $this->client->call( - 'crm.requisite.preset.delete', - array('id' => $id) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_fields.php - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.requisite.preset.fields' - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_get.php - * - * @param $id - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function get($id) - { - $fullResult = $this->client->call( - 'crm.requisite.preset.get', - array( - 'id' => $id - ) - ); - return $fullResult; - } - - - /** - * Get list of requisite items. - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_list.php - * - * @param array $order - order of items - * @param array $filter - filter array - * @param array $select - array of collumns to select - * @param integer $start - entity number to start from (usually returned in 'next' field of previous - * 'crm.contact.list' API call) - * - * @return array - * @throws Bitrix24Exception - * - */ - public function getList($order = array(), $filter = array(), $select = array(), $start = 0) - { - $fullResult = $this->client->call( - 'crm.requisite.preset.list', - array( - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'start' => $start - ) - ); - return $fullResult; - } - - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_update.php - * - * @param $id - * @param array $fields An array in format array("field"=>"value"[, ...]) containing values for the fields - * that need to be updated. The fields can be one or more of those returned by - * crm.requisite.preset.fields - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function update($id, $fields = array()) - { - $fullResult = $this->client->call( - 'crm.requisite.preset.update', - array( - 'id' => $id, - 'fields' => $fields - ) - ); - return $fullResult; - } -} diff --git a/src/classes/crm/requisite/presetfield.php b/src/classes/crm/requisite/presetfield.php deleted file mode 100644 index cc6a1ae4..00000000 --- a/src/classes/crm/requisite/presetfield.php +++ /dev/null @@ -1,225 +0,0 @@ -client->call( - 'crm.requisite.preset.field.add', - array( - 'preset' => $preset, - 'fields' => $fields, - ) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_field_availabletoadd.php - * - * @param array $preset - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function availableToAdd($preset = array()) - { - $fullResult = $this->client->call( - 'crm.requisite.preset.field.availabletoadd', - array( - 'preset' => $preset, - ) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_field_delete.php - * - * @param $id - * - * @param $preset - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @internal param array $fields array of fields - */ - public function delete($id, $preset) - { - $fullResult = $this->client->call( - 'crm.requisite.preset.field.delete', - array( - 'id' => $id, - 'preset' => $preset - ) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_field_fields.php - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.requisite.preset.field.fields' - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_field_get.php - * - * @param $id - * - * @param $preset - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function get($id, $preset) - { - $fullResult = $this->client->call( - 'crm.requisite.preset.field.get', - array( - 'id' => $id, - 'preset' => $preset - ) - ); - return $fullResult; - } - - - /** - * Get list of requisite items. - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_field_list.php - * - * - * @param array $preset - * @param int $start - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function getList($preset = array(), $start = 0) - { - $fullResult = $this->client->call( - 'crm.requisite.preset.field.list', - array( - 'preset' => $preset, - 'start' => $start - ) - ); - return $fullResult; - } - - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_preset_update.php - * - * @param $id - * @param array $fields An array in format array("field"=>"value"[, ...]) containing values for the fields - * that need to be updated. The fields can be one or more of those returned by - * crm.requisite.preset.fields - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function update($preset = array(), $fields = array()) - { - $fullResult = $this->client->call( - 'crm.requisite.preset.field.update', - array( - 'preset' => $preset, - 'fields' => $fields - ) - ); - return $fullResult; - } -} diff --git a/src/classes/crm/requisite/requisite.php b/src/classes/crm/requisite/requisite.php deleted file mode 100644 index 5da88431..00000000 --- a/src/classes/crm/requisite/requisite.php +++ /dev/null @@ -1,150 +0,0 @@ -client->call( - 'crm.requisite.add', - array( - 'fields' => $fields, - ) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_delete.php - * - * @param integer $id - * - * @return array - * @throws Bitrix24Exception - */ - public function delete($id) - { - $fullResult = $this->client->call( - 'crm.requisite.delete', - array('id' => $id) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_fields.php - * @return array - * @throws Bitrix24Exception - */ - public function fields() - { - $fullResult = $this->client->call( - 'crm.requisite.fields' - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_get.php - * - * @param integer $id - * - * @return array - * @throws Bitrix24Exception - */ - public function get($id) - { - $fullResult = $this->client->call( - 'crm.requisite.get', - array('id' => $id) - ); - return $fullResult; - } - - - /** - * Get list of requisite items. - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_list.php - * - * @param array $order - order of items - * @param array $filter - filter array - * @param array $select - array of collumns to select - * @param integer $start - entity number to start from (usually returned in 'next' field of previous - * 'crm.requisite.list' API call) - * - * @return array - * @throws Bitrix24Exception - * - */ - public function getList($order = array(), $filter = array(), $select = array(), $start = 0) - { - $fullResult = $this->client->call( - 'crm.requisite.list', - array( - 'order' => $order, - 'filter' => $filter, - 'select' => $select, - 'start' => $start - ) - ); - return $fullResult; - } - - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_update.php - * - * @param $id - * @param array $fields An array in format array("field"=>"value"[, ...]) containing values for the fields - * that need to be updated. The fields can be one or more of those returned by - * crm.requisite.fields. - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function update($id, $fields = array()) - { - $fullResult = $this->client->call( - 'crm.requisite.update', - array( - 'id' => $id, - 'fields' => $fields - ) - ); - return $fullResult; - } -} diff --git a/src/classes/crm/requisite/userfield.php b/src/classes/crm/requisite/userfield.php deleted file mode 100644 index b8c82470..00000000 --- a/src/classes/crm/requisite/userfield.php +++ /dev/null @@ -1,156 +0,0 @@ -client->call( - 'crm.requisite.userfield.add', - array('fields' => $fields) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_userfield_delete.php - * - * @param integer $userfieldId - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function delete($userfieldId) - { - $fullResult = $this->client->call( - 'crm.requisite.userfield.delete', - array('id' => $userfieldId) - ); - return $fullResult; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_userfield_get.php - * - * @param integer $userfieldId - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function get($userfieldId) - { - $fullResult = $this->client->call( - 'crm.requisite.userfield.get', - array('id' => $userfieldId) - ); - return $fullResult; - } - - /** - * Get list of user fields items. - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_userfield_list.php - * - * @param array $order - order of task items - * @param array $filter - filter array - * - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function getList($order = array(), $filter = array()) - { - $fullResult = $this->client->call( - 'crm.requisite.userfield.list', - array( - 'order' => $order, - 'filter' => $filter - ) - ); - return $fullResult; - } - - - /** - * @param $id - * @param array $fields - * - * @link https://dev.1c-bitrix.ru/rest_help/crm/requisite/methods/crm_requisite_userfield_update.php - * @return array - * @throws \Bitrix24\Exceptions\Bitrix24WrongClientException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsInvalidException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - * @throws \Bitrix24\Exceptions\Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24PortalDeletedException - * @throws \Bitrix24\Exceptions\Bitrix24PaymentRequiredException - * @throws \Bitrix24\Exceptions\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Exceptions\Bitrix24IoException - * @throws \Bitrix24\Exceptions\Bitrix24Exception - * @throws \Bitrix24\Exceptions\Bitrix24EmptyResponseException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - */ - public function update($id, $fields = array()) - { - $fullResult = $this->client->call( - 'crm.requisite.userfield.update', - array( - 'id' => $id, - 'fields' => $fields - ) - ); - - return $fullResult; - } -} diff --git a/src/classes/crm/status/status.php b/src/classes/crm/status/status.php deleted file mode 100644 index daac3df0..00000000 --- a/src/classes/crm/status/status.php +++ /dev/null @@ -1,51 +0,0 @@ -client->call( - 'crm.status.fields' - ); - return $fullResult; - } - - /** - * get list of dictionary types - * @link https://dev.1c-bitrix.ru/rest_help/crm/auxiliary/status/crm_status_entity_types.php - * @return array - */ - public function entityTypes() - { - $fullResult = $this->client->call( - 'crm.status.entity.types' - ); - return $fullResult; - } - - /** - * get dictionary data - * @link https://dev.1c-bitrix.ru/rest_help/crm/auxiliary/status/crm_status_entity_items.php - * @param string $entityId - * @return array - */ - public function entityItems($entityId) - { - $fullResult = $this->client->call( - 'crm.status.entity.items', - array( - 'entityId' => $entityId - ) - ); - return $fullResult; - } -} diff --git a/src/classes/departments/department.php b/src/classes/departments/department.php deleted file mode 100644 index 49978f91..00000000 --- a/src/classes/departments/department.php +++ /dev/null @@ -1,98 +0,0 @@ -client->call('department.fields'); - return $result['result']; - } - - /** - * Get filtered list of departments - * @link http://dev.1c-bitrix.ru/rest_help/departments/department_get.php - * @param $sort - * @param $order - * @param $filter - * @throws Bitrix24Exception - * @return array - */ - public function get($sort, $order, $filter) - { - $filterCode = array_keys($filter); - $filterCode = $filterCode[0]; - $filterValue = array_values($filter); - $filterValue = $filterValue[0]; - $arFilter = array(Main::SORT => $sort, Main::ORDER => $order, $filterCode => $filterValue); - $result = $this->client->call('department.get', $arFilter); - return $result; - } - - /** - * Create department. Works with user, who has rights for modify company structure - * @link http://dev.1c-bitrix.ru/rest_help/departments/department_add.php - * @param $name - * @param $sort - * @param $parent - * @param $head - * @throws Bitrix24Exception - * @return integer - */ - public function add($name, $sort, $parent, $head) - { - $result = $this->client->call('department.add', array( - Fields::NAME => $name, - Fields::SORT => $sort, - Fields::PARENT => $parent, - Fields::HEAD => $head - )); - return $result['result']; - } - - /** - * Update department. Works with user, who has rights for modify company structure - * @link http://dev.1c-bitrix.ru/rest_help/departments/department_update.php - * @param $id - required - * @param $name - required - * @param $sort - * @param $parent - * @param $head - * @throws Bitrix24Exception - * @return boolean - */ - public function update($id, $name, $sort, $parent, $head) - { - $result = $this->client->call('department.update', array( - Fields::ID => $id, - Fields::NAME => $name, - Fields::SORT => $sort, - Fields::PARENT => $parent, - Fields::HEAD => $head - )); - return $result['result']; - } - - /** - * Delete department. Works with user, who has rights for modify company structure - * @param $id integer - * @throws Bitrix24Exception - * @return boolean - */ - public function delete($id) - { - $result = $this->client->call('department.delete', array(Fields::ID => $id)); - return $result['result']; - } -} diff --git a/src/classes/entity/entity.php b/src/classes/entity/entity.php deleted file mode 100644 index f0be0f13..00000000 --- a/src/classes/entity/entity.php +++ /dev/null @@ -1,310 +0,0 @@ -client->call('entity.add', array( - "ENTITY" => $entity, - "NAME" => $name, - "ACCESS" => $access - )); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_update.php - * @param $entity - * @param $name - * @param $access - * @return array - * @throws Bitrix24Exception - */ - public function update($entity, $name, $access) - { - $fullResult = $this->client->call('entity.update', array( - "ENTITY" => $entity, - "NAME" => $name, - "ACCESS" => $access - )); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_rights.php - * @param $entity - * @param $access - * @return array - * @throws Bitrix24Exception - */ - public function rights($entity, $access) - { - $result = $this->client->call('entity.rights', array( - "ENTITY" => $entity, - "ACCESS" => $access - )); - return $result; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_get.php - * @param $entity - * @return array - * @throws Bitrix24Exception - */ - public function get($entity) - { - $fullResult = $this->client->call('entity.get', array( - "ENTITY" => $entity - )); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_delete.php - * @param $entity - * @return array - * @throws Bitrix24Exception - */ - public function delete($entity) - { - $fullResult = $this->client->call('entity.delete', array( - "ENTITY" => $entity - )); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_section_add.php - * @param $entity - * @param $name - * @param array $fields - * @return array - * @throws Bitrix24Exception - */ - public function sectionAdd($entity, $name, $fields = array()) - { - $arAdd = array( - "ENTITY" => $entity, - "NAME" => $name - ); - $arAdd = array_merge($arAdd, $fields); - $fullResult = $this->client->call('entity.section.add', $arAdd); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_section_get.php - * @param $entity - * @param array $sort - * @param array $filter - * @return array - * @throws Bitrix24Exception - */ - public function sectionGet($entity, $sort = array(), $filter = array()) - { - $fullResult = $this->client->call('entity.section.get', array( - "ENTITY" => $entity, - "SORT" => $sort, - "FILTER" => $filter - )); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_section_update.php - * @param $entity - * @param $id - * @param array $fields - * @return array - * @throws Bitrix24Exception - */ - public function sectionUpdate($entity, $id, $fields = array()) - { - $arUpdate = array( - "ENTITY" => $entity, - "ID" => $id - ); - $arUpdate = array_merge($arUpdate, $fields); - $fullResult = $this->client->call('entity.section.update', $arUpdate); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_section_delete.php - * @param $entity - * @param $id - * @return array - * @throws Bitrix24Exception - */ - public function sectionDelete($entity, $id) - { - $fullResult = $this->client->call('entity.section.delete', array( - "ENTITY" => $entity, - "ID" => $id - )); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_item_add.php - * @param $entity - * @param $name - * @param array $fields - * @return array - * @throws Bitrix24Exception - */ - public function itemAdd($entity, $name, $fields = array()) - { - $arAdd = array( - "ENTITY" => $entity, - "NAME" => $name - ); - $arAdd = array_merge($arAdd, $fields); - $fullResult = $this->client->call('entity.item.add', $arAdd); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_item_get.php - * @param $entity - * @param array $sort - * @param array $filter - * @return array - * @throws Bitrix24Exception - */ - public function itemGet($entity, $sort = array(), $filter = array()) - { - $fullResult = $this->client->call('entity.item.get', array( - "ENTITY" => $entity, - "SORT" => $sort, - "FILTER" => $filter - )); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_item_update.php - * @param $entity - * @param $id - * @param array $fields - * @return array - * @throws Bitrix24Exception - */ - public function itemUpdate($entity, $id, $fields = array()) - { - $arUpdate = array( - "ENTITY" => $entity, - "ID" => $id - ); - $arUpdate = array_merge($arUpdate, $fields); - $fullResult = $this->client->call('entity.item.update', $arUpdate); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_item_delete.php - * @param $entity - * @param $id - * @return array - * @throws Bitrix24Exception - */ - public function itemDelete($entity, $id) - { - $fullResult = $this->client->call('entity.item.delete', array( - "ENTITY" => $entity, - "ID" => $id - )); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_item_property_get.php - * @param $entity - * @param $property - * @return array - * @throws Bitrix24Exception - */ - public function itemPropertyGet($entity, $property) - { - $fullResult = $this->client->call('entity.item.property.get', array( - "ENTITY" => $entity, - "PROPERTY" => $property - )); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_item_property_add.php - * @param $entity - * @param $property - * @param $name - * @param $type - * @return array - * @throws Bitrix24Exception - */ - public function itemPropertyAdd($entity, $property, $name, $type) - { - $fullResult = $this->client->call('entity.item.property.add', array( - "ENTITY" => $entity, - "PROPERTY" => $property, - "NAME" => $name, - "TYPE" => $type, - - )); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_item_property_update.php - * @param $entity - * @param $property - * @param $property_new - * @param $name - * @param $type - * @return array - * @throws Bitrix24Exception - */ - public function itemPropertyUpdate($entity, $property, $property_new, $name, $type) - { - $fullResult = $this->client->call('entity.item.property.update', array( - "ENTITY" => $entity, - "PROPERTY" => $property, - "PROPERTY_NEW" => $property_new, - "NAME" => $name, - "TYPE" => $type, - )); - return $fullResult; - } - - /** - * @link http://dev.1c-bitrix.ru/rest_help/entity/entity_item_property_delete.php - * @param $entity - * @param $property - * @return array - * @throws Bitrix24Exception - */ - public function itemPropertyDelete($entity, $property) - { - $fullResult = $this->client->call('entity.item.property.delete', array( - "ENTITY" => $entity, - "PROPERTY" => $property - )); - return $fullResult; - } -} \ No newline at end of file diff --git a/src/classes/event/event.php b/src/classes/event/event.php deleted file mode 100644 index 18fd9bd8..00000000 --- a/src/classes/event/event.php +++ /dev/null @@ -1,101 +0,0 @@ -getConstant(strtoupper($eventHandlerName)); - return isset($result); - } - - /** - * Get list of register events - * @return array - */ - public function get() - { - $fullResult = $this->client->call( - 'event.get', - array() - ); - return $fullResult; - } - - /** - * Get list of all supported events - * @link http://dev.1c-bitrix.ru/rest_help/general/events.php - * @return array - */ - public function getList() - { - $fullResult = $this->client->call( - 'events', - array() - ); - return $fullResult; - } - /** - * Register new event handler. Work only for user with portal administrator rights - * @link http://dev.1c-bitrix.ru/rest_help/general/event_bind.php - * @param $eventName string event handler code - * @param $handler string event handler URL - * @param $authType integer user identifier, under witch event handler was executed - * @throws Bitrix24Exception - * @return array - */ - public function bind($eventName, $handler, $authType = null) - { - if(!$this->isEventHandlerCodeValid($eventName)) - { - throw new Bitrix24Exception('eventName is invalid'); - } - if(is_null($handler)) - { - throw new Bitrix24Exception('handler URL is null'); - } - $fullResult = $this->client->call( - 'event.bind', - array( - 'event' => $eventName, - 'handler' => $handler, - 'auth_type' => $authType - ) - ); - return $fullResult; - } - - /** - * Unregister event handler. Work only for user with portal administrator rights - * @link http://dev.1c-bitrix.ru/rest_help/general/event_unbind.php - * @param $eventName - * @param $handler - * @param null $authType - * @return array - */ - public function unbind($eventName = NULL, $handler = NULL, $authType = null) - { - $fullResult = $this->client->call( - 'event.unbind', - array( - 'event' => $eventName, - 'handler' => $handler, - 'auth_type' => $authType - ) - ); - return $fullResult; - } -} \ No newline at end of file diff --git a/src/classes/event/util.php b/src/classes/event/util.php deleted file mode 100644 index 19934f32..00000000 --- a/src/classes/event/util.php +++ /dev/null @@ -1,29 +0,0 @@ - $arEvent) - { - if(($arEvent['event'] === $newEventName) && ($arEvent['handler'] === $newEventHandler)) - { - $isEventBind = true; - } - } - return $isEventBind; - } -} diff --git a/src/classes/im/attach/attach.php b/src/classes/im/attach/attach.php deleted file mode 100644 index 9cfa3d44..00000000 --- a/src/classes/im/attach/attach.php +++ /dev/null @@ -1,129 +0,0 @@ - and contributors - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Im\Attach; -use Bitrix24\Bitrix24Entity; -use Bitrix24\Bitrix24Exception; -use Bitrix24\Presets\Im\Fields as B24ImFields; -use Bitrix24\Im\Attach\iAttachItem; - -/** - * Class Attach - * @package Bitrix24\Im\Attach - */ -class Attach implements iAttach -{ - /** - * @var string - */ - const CHAT = 'CHAT'; - /** - * @var int $id Unix timestamp - */ - protected $id; - /** - * @var string $color hex color see iAttach interface - */ - protected $color; - /** - * @var array - */ - protected $attachItems; - /** - * Attach constructor. - * @param null | int $id Unix timestamp - * @param null | string $color hex color see iAttach interface - */ - public function __construct($id = null, $color = null) - { - $this->attachItems = array(); - - if(null === $id) - { - $this->id = time(); - } - - if (self::CHAT !== $color) - { - $this->color = $color; - if(null === $this->color) - { - $this->setStatusNormal(); - } - } - } - - /** - * @param iAttachItem $attachItem - */ - public function add(iAttachItem $attachItem) - { - $this->attachItems[] = clone $attachItem; - } - - /** - * @return array - */ - public function getData() - { - return array( - 'ID' => $this->id, - 'BLOCKS' => $this->getAttachList(), - 'COLOR' => $this->color - ); - } - - /** - * @return array - */ - public function getAttachItems() - { - return $this->attachItems; - } - - /** - * @return array - */ - private function getAttachList() - { - $arResult = array(); - /** - * @var $obAttachItem iAttachItem - */ - foreach($this->getAttachItems() as $cnt => $obAttachItem) - { - $arResult[][$obAttachItem->getAttachTypeCode()] = $obAttachItem->getAttachData(); - } - return $arResult; - } - - /** - * @return mixed - */ - public function setStatusNormal() - { - $this->color = self::STATUS_NORMAL; - } - - /** - * @return mixed - */ - public function setStatusAttention() - { - $this->color = self::STATUS_ATTENTION; - } - - /** - * @return mixed - */ - public function setStatusProblem() - { - $this->color = self::STATUS_PROBLEM; - } -} \ No newline at end of file diff --git a/src/classes/im/attach/iattach.php b/src/classes/im/attach/iattach.php deleted file mode 100644 index cb730078..00000000 --- a/src/classes/im/attach/iattach.php +++ /dev/null @@ -1,49 +0,0 @@ - and contributors - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Im\Attach; -/** - * Interface iAttach - * @package Bitrix24\Im\Attach - */ -interface iAttach -{ - /** - * @var string - */ - const STATUS_NORMAL = "#aac337"; - /** - * @var string - */ - const STATUS_ATTENTION = "#e8a441"; - /** - * @var string - */ - const STATUS_PROBLEM = "#df532d"; - - /** - * @return mixed - */ - public function setStatusNormal(); - - /** - * @return mixed - */ - public function setStatusAttention(); - - /** - * @return mixed - */ - public function setStatusProblem(); - - /** - * @return array - */ - public function getAttachItems(); -} diff --git a/src/classes/im/attach/iattachitem.php b/src/classes/im/attach/iattachitem.php deleted file mode 100644 index 61b0e6e7..00000000 --- a/src/classes/im/attach/iattachitem.php +++ /dev/null @@ -1,30 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Im\Attach; -use Bitrix24\Bitrix24Entity; -use Bitrix24\Bitrix24Exception; -use Bitrix24\Presets\Im\Fields as B24ImFields; - -/** - * Interface iAttachItem - * @package Bitrix24\Im\Attach - */ -interface iAttachItem -{ - /** - * @return mixed - */ - public function getAttachData(); - - /** - * @return string - */ - public function getAttachTypeCode(); -} \ No newline at end of file diff --git a/src/classes/im/attach/item/delimiter.php b/src/classes/im/attach/item/delimiter.php deleted file mode 100644 index 5f7e5969..00000000 --- a/src/classes/im/attach/item/delimiter.php +++ /dev/null @@ -1,60 +0,0 @@ - and contributors - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Im\Attach\Item; -use Bitrix24\Im\Attach\iAttachItem; -/** - * Class Delimiter - * @package Bitrix24\Im\Attach\Item - */ -class Delimiter implements iAttachItem -{ - /** - * @var string - */ - const ATTACH_TYPE_CODE = 'DELIMITER'; - /** - * @var - */ - protected $color; - /** - * @var - */ - protected $size; - - /** - * Delimiter constructor. - * @param $size - * @param $color - */ - public function __construct($size = null, $color = null) - { - $this->size = $size; - $this->color = $color; - } - - /** - * @return array - */ - public function getAttachData() - { - return array( - 'SIZE' => $this->size, - 'COLOR' => $this->color, - ); - } - - /** - * @return string - */ - public function getAttachTypeCode() - { - return self::ATTACH_TYPE_CODE; - } -} \ No newline at end of file diff --git a/src/classes/im/attach/item/file.php b/src/classes/im/attach/item/file.php deleted file mode 100644 index 4306e86f..00000000 --- a/src/classes/im/attach/item/file.php +++ /dev/null @@ -1,67 +0,0 @@ - and contributors - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Im\Attach\Item; -use Bitrix24\Im\Attach\iAttachItem; -/** - * Class File - * @package Bitrix24\Im\Attach\Item - */ -class File implements iAttachItem -{ - /** - * @var string - */ - const ATTACH_TYPE_CODE = 'FILE'; - /** - * @var - */ - protected $name; - /** - * @var - */ - protected $link; - /** - * @var - */ - protected $size; - - /** - * Image constructor. - * @param $name - * @param $link - * @param $size - */ - public function __construct($link, $name, $size) - { - $this->name = $name; - $this->link = $link; - $this->size = $size; - } - - /** - * @return array - */ - public function getAttachData() - { - return array( - 'NAME' => $this->name, - 'LINK' => $this->link, - 'SIZE' => $this->size, - ); - } - - /** - * @return string - */ - public function getAttachTypeCode() - { - return self::ATTACH_TYPE_CODE; - } -} \ No newline at end of file diff --git a/src/classes/im/attach/item/grid.php b/src/classes/im/attach/item/grid.php deleted file mode 100644 index ea3159bc..00000000 --- a/src/classes/im/attach/item/grid.php +++ /dev/null @@ -1,114 +0,0 @@ - and contributors - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Im\Attach\Item; -use Bitrix24\Im\Attach\iAttachItem; -/** - * Class Grid - * @package Bitrix24\Im\Attach\Item - */ -class Grid implements iAttachItem -{ - /** - * @var string - */ - const ATTACH_TYPE_CODE = 'GRID'; - /** - * @var array - */ - protected $arGridItems = array(); - - /** - * Grid constructor. - */ - public function __construct() - { - } - - /** - * @param $name - * @param $value - * @param null $color - * @param null $link - * @param null $chatId - * @param null $userId - */ - public function addBlockItem($name, $value, $color = null, $link = null, $chatId = null, $userId = null) - { - $this->arGridItems[] = array( - 'DISPLAY' => 'BLOCK', - 'NAME' => $name, - 'VALUE' => $value, - 'COLOR' => $color, - 'LINK' => $link, - 'CHAT_ID' => $chatId, - 'USER_ID' => $userId - ); - } - - /** - * @param $name - * @param $value - * @param $width - * @param null $color - * @param null $link - * @param null $chatId - * @param null $userId - */ - public function addLineItem($name, $value, $width, $color = null, $link = null, $chatId = null, $userId = null) - { - $this->arGridItems[] = array( - 'DISPLAY' => 'LINE', - 'NAME' => $name, - 'VALUE' => $value, - 'WIDTH' => $width, - 'COLOR' => $color, - 'LINK' => $link, - 'CHAT_ID' => $chatId, - 'USER_ID' => $userId - ); - } - - /** - * @param $name - * @param $value - * @param null $color - * @param null $link - * @param null $chatId - * @param null $userId - */ - public function addColumnItem($name, $value, $width, $color = null, $link = null, $chatId = null, $userId = null) - { - $this->arGridItems[] = array( - 'DISPLAY' => 'COLUMN', - 'NAME' => $name, - 'VALUE' => $value, - 'WIDTH' => $width, - 'COLOR' => $color, - 'LINK' => $link, - 'CHAT_ID' => $chatId, - 'USER_ID' => $userId - ); - } - /** - * @return array - */ - public function getAttachData() - { - return $this->arGridItems; - } - - /** - * @return string - */ - public function getAttachTypeCode() - { - return self::ATTACH_TYPE_CODE; - } -} \ No newline at end of file diff --git a/src/classes/im/attach/item/image.php b/src/classes/im/attach/item/image.php deleted file mode 100644 index 6a0ce147..00000000 --- a/src/classes/im/attach/item/image.php +++ /dev/null @@ -1,60 +0,0 @@ - and contributors - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Im\Attach\Item; -use Bitrix24\Im\Attach\iAttachItem; -/** - * Class Image - * @package Bitrix24\Im\Attach\Item - */ -class Image implements iAttachItem -{ - /** - * @var string - */ - const ATTACH_TYPE_CODE = 'IMAGE'; - /** - * @var - */ - protected $name; - /** - * @var - */ - protected $link; - - /** - * Image constructor. - * @param $name - * @param $link - */ - public function __construct($name, $link) - { - $this->name = $name; - $this->link = $link; - } - - /** - * @return array - */ - public function getAttachData() - { - return array( - 'NAME' => $this->name, - 'LINK' => $this->link - ); - } - - /** - * @return string - */ - public function getAttachTypeCode() - { - return self::ATTACH_TYPE_CODE; - } -} \ No newline at end of file diff --git a/src/classes/im/attach/item/link.php b/src/classes/im/attach/item/link.php deleted file mode 100644 index 69ff3510..00000000 --- a/src/classes/im/attach/item/link.php +++ /dev/null @@ -1,75 +0,0 @@ - and contributors - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Im\Attach\Item; -use Bitrix24\Im\Attach\iAttachItem; - -/** - * Class Link - * @package Bitrix24\Im\Attach\Item - */ -class Link implements iAttachItem -{ - /** - * @var string - */ - const ATTACH_TYPE_CODE = 'LINK'; - /** - * @var - */ - protected $name; - /** - * @var - */ - protected $description; - /** - * @var - */ - protected $link; - /** - * @var string - */ - protected $preview; - - /** - * Link constructor. - * @param $name string required - * @param $link string required - * @param $description string - * @param $preview string required - */ - public function __construct($name, $link, $description, $preview) - { - $this->name = $name; - $this->link = $link; - $this->description = $description; - $this->preview = $preview; - } - - /** - * @return array - */ - public function getAttachData() - { - return array( - 'NAME' => $this->name, - 'DESC' => $this->description, - 'LINK' => $this->link, - 'PREVIEW' => $this->preview - ); - } - - /** - * @return string - */ - public function getAttachTypeCode() - { - return self::ATTACH_TYPE_CODE; - } -} \ No newline at end of file diff --git a/src/classes/im/attach/item/message.php b/src/classes/im/attach/item/message.php deleted file mode 100644 index dd3f0c38..00000000 --- a/src/classes/im/attach/item/message.php +++ /dev/null @@ -1,52 +0,0 @@ - and contributors - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Im\Attach\Item; -use Bitrix24\Im\Attach\iAttachItem; - -/** - * Class Message - * @package Bitrix24\Im\Attach\Item - */ -class Message implements iAttachItem -{ - /** - * @var string - */ - const ATTACH_TYPE_CODE = 'MESSAGE'; - /** - * @var - */ - protected $message; - - /** - * Message constructor. - * @param $message - */ - public function __construct($message) - { - $this->message = $message; - } - - /** - * @return array - */ - public function getAttachData() - { - return $this->message; - } - - /** - * @return string - */ - public function getAttachTypeCode() - { - return self::ATTACH_TYPE_CODE; - } -} \ No newline at end of file diff --git a/src/classes/im/attach/item/user.php b/src/classes/im/attach/item/user.php deleted file mode 100644 index 0872e2c9..00000000 --- a/src/classes/im/attach/item/user.php +++ /dev/null @@ -1,68 +0,0 @@ - and contributors - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Im\Attach\Item; -use Bitrix24\Im\Attach\iAttachItem; - -/** - * Class User - * @package Bitrix24\Im\Attach\Item - */ -class User implements iAttachItem -{ - /** - * @var string - */ - const ATTACH_TYPE_CODE = 'USER'; - /** - * @var - */ - protected $userName; - /** - * @var - */ - protected $avatarUrl; - /** - * @var - */ - protected $userLink; - - /** - * User constructor. - * @param $userName string required - * @param $avatarUrl string - * @param $userLink string - */ - public function __construct($userName, $avatarUrl = null, $userLink = null) - { - $this->userName = $userName; - $this->avatarUrl = $avatarUrl; - $this->userLink = $userLink; - } - - /** - * @return array - */ - public function getAttachData() - { - return array( - 'NAME' => $this->userName, - 'AVATAR' => $this->avatarUrl, - 'LINK' => $this->userLink - ); - } - - /** - * @return string - */ - public function getAttachTypeCode() - { - return self::ATTACH_TYPE_CODE; - } -} \ No newline at end of file diff --git a/src/classes/im/chat.php b/src/classes/im/chat.php deleted file mode 100644 index 07ca311d..00000000 --- a/src/classes/im/chat.php +++ /dev/null @@ -1,289 +0,0 @@ - and contributors - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Im; -use Bitrix24\Bitrix24Entity; -use Bitrix24\Bitrix24Exception; -use Bitrix24\Presets\Im\Fields as B24ImFields; -use Bitrix24\Im\Attach\Attach; - -/** - * Class Chat - * @package Bitrix24\Im - */ -class Chat extends Bitrix24Entity -{ - /** - * create new chat - * - * @param string $title - * @param string $description - * @param string $color chat color in Bitrix24\Presets\Im\iChatColor for mobile - * @param string $message - * @param array $users - * @param string $avatarImgInBase64 - * @param bool $isOpen - * - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - * - * @return array - */ - public function add($title, $description='', $color ='', $message = '', array $users = array(), $avatarImgInBase64 = null, $isOpen = false) - { - $arParams = array( - 'title' => (string) $title, - 'description' => (string) $description, - 'color' => (string) $color, - 'message' => (string) $message, - 'users' => $users, - 'avatar' => $avatarImgInBase64, - ); - - if($isOpen) - { - $arParams['type'] = 'OPEN'; - } - return $this->client->call('im.chat.add', $arParams); - } - - /** - * delete chat - * - * @param int $chatId - * - * @return array - * - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function delete($chatId) - { - return $this->client->call('im.chat.delete', array( - 'chat_id' => (int) $chatId - )); - } - - /** - * set chat owner - * - * @param $chatId - * @param $userId - * - * @return array - * - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function setOwner($chatId, $userId) - { - return $this->client->call('im.chat.setOwner', array( - 'chat_id' => (int) $chatId, - 'user_id' => (int) $userId - )); - } - - /** - * update color - * - * @param int $chatId - * @param string $newColor - * - * @return array - * - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function updateColor($chatId, $newColor) - { - return $this->client->call('im.chat.updateColor', array( - 'chat_id' => (int) $chatId, - 'color' => (string) $newColor - )); - } - - /** - * update title - * - * @param int $chatId - * @param string $newTitle - * - * @return array - * - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function updateTitle($chatId, $newTitle) - { - return $this->client->call('im.chat.updateTitle', array( - 'chat_id' => (int) $chatId, - 'title' => (string) $newTitle - )); - } - - /** - * update avatar - * - * @param int $chatId - * @param string $avatarImgInBase64 - * - * @return array - * - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function updateAvatar($chatId, $avatarImgInBase64) - { - return $this->client->call('im.chat.updateAvatar', array( - 'chat_id' => (int) $chatId, - 'avatar' => (string) $avatarImgInBase64 - )); - } - - - /** - * send typing - * - * @param int $chatId - * - * @return array - * - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function sendTyping($chatId) - { - return $this->client->call('im.chat.sendTyping', array( - 'chat_id' => (int) $chatId - )); - } - - /** - * delete user from chat - * - * @param $chatId - * @param $userId - * - * @return array - * - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function userDelete($chatId, $userId) - { - return $this->client->call('im.chat.user.delete', array( - 'chat_id' => (int) $chatId, - 'user_id' => (int) $userId - )); - } - - /** - * - * @param $chatId - * @param array $arNewUsers - * - * @return array - * - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException */ - public function userAdd($chatId, array $arNewUsers = array()) - { - return $this->client->call('im.chat.user.add', array( - 'chat_id' => (int) $chatId, - 'user_id' => $arNewUsers - )); - } - - /** - * get user list in chat - * - * @param $chatId - * - * @return array - * - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function userList($chatId) - { - return $this->client->call('im.chat.user.list', array( - 'chat_id' => (int) $chatId - )); - } -} \ No newline at end of file diff --git a/src/classes/im/im.php b/src/classes/im/im.php deleted file mode 100644 index 2a077d1e..00000000 --- a/src/classes/im/im.php +++ /dev/null @@ -1,48 +0,0 @@ -client->call( - 'im.notify', - array( - 'to' => $userId, - 'message' => $message, - 'type' => strtoupper($notifyType) - ) - ); - return $fullResult; - } -} \ No newline at end of file diff --git a/src/classes/im/notify.php b/src/classes/im/notify.php deleted file mode 100644 index ed70da03..00000000 --- a/src/classes/im/notify.php +++ /dev/null @@ -1,175 +0,0 @@ - and contributors - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Im; - -use Bitrix24\Bitrix24Entity; -use Bitrix24\Bitrix24Exception; -use Bitrix24\Presets\Im\Fields as B24ImFields; -use Bitrix24\Im\Attach\Attach; - -/** - * Class Notify - * @package Bitrix24\Im - */ -class Notify extends Bitrix24Entity -{ - /** - * @param $userId - * @param $message - * @param string $tag - * @param string $subTag - * @param Attach|null $attachObject - * @return array - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function addPersonal($userId, $message, $tag = '', $subTag = '', Attach $attachObject = null) - { - $arArgs = array( - 'user_id' => (int)$userId, - 'message' => (string)$message, - 'tag' => (string)$tag, - 'sub_tag' => (string)$subTag - ); - - if (null === $userId) { - throw new Bitrix24Exception('user id is null'); - } elseif (null === $message) { - throw new Bitrix24Exception('message is null'); - } elseif (null !== $attachObject) { - $arArgs['attach'] = $attachObject->getData(); - } - return $this->client->call('im.notify.personal.add', $arArgs); - } - - /** - * @param $userId - * @param $message - * @param string $tag - * @param string $subTag - * @param Attach|null $attachObject - * @return array - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function addSystem($userId, $message, $tag = '', $subTag = '', Attach $attachObject = null) - { - $arArgs = array( - 'user_id' => (int)$userId, - 'message' => (string)$message, - 'tag' => (string)$tag, - 'sub_tag' => (string)$subTag - ); - - if (null === $userId) { - throw new Bitrix24Exception('user id is null'); - } elseif (null === $message) { - throw new Bitrix24Exception('message is null'); - } elseif (null !== $attachObject) { - $arArgs['attach'] = $attachObject->getData(); - } - return $this->client->call('im.notify.system.add', $arArgs); - } - - /** - * @param $id - * @return array - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function deleteById($id) - { - if (null === $id) { - throw new Bitrix24Exception('id is null'); - } - $fullResult = $this->client->call( - 'im.notify.delete', - array( - 'id' => (int)$id - ) - ); - return $fullResult; - } - - /** - * @param $tag - * @return array - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function deleteByTag($tag) - { - if (null === $tag) { - throw new Bitrix24Exception('tag is null'); - } - $fullResult = $this->client->call( - 'im.notify.delete', - array( - 'tag' => (string)$tag - ) - ); - return $fullResult; - } - - /** - * @param $subTag - * @return array - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - * @throws \Bitrix24\Bitrix24Exception - * @throws \Bitrix24\Bitrix24ApiException - * @throws \Bitrix24\Bitrix24TokenIsInvalid - * @throws \Bitrix24\Bitrix24TokenIsExpired - * @throws \Bitrix24\Bitrix24WrongClientException - * @throws \Bitrix24\Bitrix24MethodNotFoundException - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function deleteBySubTag($subTag) - { - if (null === $subTag) { - throw new Bitrix24Exception('subTag is null'); - } - $fullResult = $this->client->call( - 'im.notify.delete', - array( - 'sub_tag' => (string)$subTag - ) - ); - return $fullResult; - } -} \ No newline at end of file diff --git a/src/classes/placement/Placement.php b/src/classes/placement/Placement.php deleted file mode 100644 index 3673818a..00000000 --- a/src/classes/placement/Placement.php +++ /dev/null @@ -1,74 +0,0 @@ -client->call('placement.bind', - array( - 'PLACEMENT' => $placementCode, - 'HANDLER' => $handlerUrl, - 'TITLE' => $title, - 'DESCRIPTION' => $description - )); - return $arResult; - } - - /** - * unregister placement handler - * - * @param $placementCode string - * @param $handlerUrl string - * - * @return array - */ - public function unbind($placementCode, $handlerUrl) - { - $arResult = $this->client->call('placement.unbind', - array( - 'PLACEMENT' => $placementCode, - 'HANDLER' => $handlerUrl - )); - return $arResult; - } - - /** - * Get possible placement locations - * - * @return array - */ - public function getPossibleLocations() - { - $arResult = $this->client->call('placement.list'); - return $arResult['result']; - } - - /** - * get locations with registered placements - * - * @return array - */ - public function getLocations() - { - $arResult = $this->client->call('placement.get'); - return $arResult['result']; - } -} \ No newline at end of file diff --git a/src/classes/sonet/sonetgroup.php b/src/classes/sonet/sonetgroup.php deleted file mode 100644 index c857cf12..00000000 --- a/src/classes/sonet/sonetgroup.php +++ /dev/null @@ -1,179 +0,0 @@ -client->call('sonet_group.get', - array( - 'ORDER' => $order, - 'FILTER'=> $filter, - )); - return $result; - } - - /** - * @param $name - * @param $initiate_perms - * @param $arFields - * @link https://dev.1c-bitrix.ru/rest_help/socialnetwork/sonet_group/sonet_group_create.php - * @throws Bitrix24Exception - * @return array - */ - public function Create($name, $initiate_perms, $arFields) - { - $result = $this->client->call('sonet_group.create', - array_merge( - array( - 'NAME' => $name, - 'INITIATE_PERMS' => $initiate_perms - ), - $arFields - )); - return $result; - } - - /** - * @param $group_id - * @param $arFields - * @link https://dev.1c-bitrix.ru/api_help/socialnetwork/classes/CSocNetGroup/Update.php - * @throws Bitrix24Exception - * @return array - */ - public function Update($group_id, $arFields) - { - $result = $this->client->call('sonet_group.update', - array_merge( - array('GROUP_ID' => $group_id), - $arFields - )); - return $result; - } - - /** - * @param $group_id - * @link https://dev.1c-bitrix.ru/rest_help/socialnetwork/sonet_group/sonet_group_delete.php - * @throws Bitrix24Exception - * @return array - */ - public function Delete($group_id) - { - $result = $this->client->call('sonet_group.delete', - array( - 'GROUP_ID' => $group_id - )); - return $result; - } - - /** - * @param $group_id - * @param $user_id - * @link https://dev.1c-bitrix.ru/rest_help/socialnetwork/sonet_group/sonet_group_setowner.php - * @throws Bitrix24Exception - * @return array - */ - public function SetOwner($group_id, $user_id) - { - $result = $this->client->call('sonet_group.setowner', - array( - 'GROUP_ID' => $group_id, - 'USER_ID'=> $user_id - )); - return $result; - } - - /** - * @param $id - * @link https://dev.1c-bitrix.ru/rest_help/socialnetwork/sonet_group/sonet_group_user_get.php - * @throws Bitrix24Exception - * @return array - */ - public function UserGet($id) - { - $result = $this->client->call('sonet_group.user.get', - array( - 'ID' => $id - ) - ); - return $result; - } - - /** - * @param $group_id - * @param $user_id - * @param $message - * @link https://dev.1c-bitrix.ru/rest_help/socialnetwork/sonet_group/sonet_group_user_invite.php - * @throws Bitrix24Exception - * @return array - */ - public function Invate($group_id, $user_id, $message) - { - $result = $this->client->call('sonet_group.user.invite', - array( - 'GROUP_ID' => $group_id, - 'USER_ID'=> $user_id, - 'MESSAGE'=> $message - ) - ); - return $result; - } - - /** - * @param $group_id - * @param $message - * @link https://dev.1c-bitrix.ru/rest_help/socialnetwork/sonet_group/sonet_group_user_request.php - * @throws Bitrix24Exception - * @return array - */ - public function Request($group_id, $message) - { - $result = $this->client->call('sonet_group.user.request', - array( - 'GROUP_ID' => $group_id, - 'MESSAGE'=> $message - ) - ); - return $result; - } - - /** - * @link https://dev.1c-bitrix.ru/rest_help/socialnetwork/sonet_group/sonet_group_user_groups.php - * @throws Bitrix24Exception - * @return array - */ - public function UserGroups() - { - $result= $this->client->call('sonet_group.user.groups'); - return $result; - } - - /** - * @param $group_id - * @param $feature - * @param $operation - * @link https://dev.1c-bitrix.ru/rest_help/socialnetwork/sonet_group/sonet_group_feature_access.php - * @throws Bitrix24Exception - * @return array - */ - public function FeatureAccess($group_id, $feature, $operation) - { - $result = $this->client->call('sonet_group.feature.access', - array( - 'GROUP_ID' => $group_id, - 'FEATURE' => $feature, - 'OPERATION' => $operation - )); - return $result; - } -} \ No newline at end of file diff --git a/src/classes/task/checklistitem.php b/src/classes/task/checklistitem.php deleted file mode 100644 index 34d761ea..00000000 --- a/src/classes/task/checklistitem.php +++ /dev/null @@ -1,169 +0,0 @@ -client->call('task.checklistitem.getmanifest'); - return $result; - } - - /** - * Returns the list of check list elements in a task. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/getlist.php - * @param $taskId integer Task identifier. Required parameter. - * @param $order array Array for result sorting. The sorting field can take the following values: - * ID � check list element identifier; - * CREATED_BY � identifier of the user who has created the element; - * TOGGLED_BY � identifier of the user who has modified the check list element status; - * TOGGLED_DATE � the time when the check list element status was changed; - * TITLE � check list element header; - * SORT_INDEX � element sorting index; - * IS_COMPLETE � the element is marked as completed; - * The sorting direction can take the following values: - * asc � ascending; - * desc � descending; - * Optional. By default it is filtered by descending identifier of a check list element. - * @return array - */ - public function getList($taskId, $order) - { - $result = $this->client->call('task.checklistitem.getlist', - array( - 'TASKID' => $taskId, - 'ORDER' => $order - )); - return $result; - } - - /** - * Returns a check list element by its identifier. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/get.php - * @param $taskId integer Task identifier. Required parameter. - * @param $checklistItemId integer Element identifier. Required parameter. - * @return array - */ - public function get($taskId, $checklistItemId) - { - $result = $this->client->call('task.checklistitem.get', - array( - 'TASKID' => $taskId, - 'ITEMID' => $checklistItemId - )); - return $result; - } - - /** - * Adds a new check list element to a task. Returns the identifier of the added element. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/add.php - * @param $taskId integer Task identifier. Required parameter. - * @param $fields array Array of fields of a check list element (TITLE, SORT_INDEX, IS_COMPLETE). Required parameter. - * @return array - */ - public function add($taskId, $fields) - { - $result = $this->client->call('task.checklistitem.add', array($taskId, array($fields))); - return $result; - } - - /** - * Updates data of a check list element. - * Before updating data, it is advisable to make sure the action is permitted (task.checklistitem.isactionallowed). - * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/update.php - * @param $taskId integer Task identifier. Required parameter. - * @param $checklistItemId integer Check list element identifier. Required parameter. - * @param $fields array Array of fields of a check list elements (TITLE, SORT_INDEX, IS_COMPLETE). Required parameter. - * @return array - */ - public function update($taskId, $checklistItemId, $fields) - { - $result = $this->client->call('task.checklistitem.update', array($taskId, $checklistItemId, array($fields))); - return $result; - } - - /** - * Deletes check list element. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/complete.php - * @param $taskId integer Task identifier. Required parameter. - * @param $checklistItemId integer Check list element identifier. Required parameter. - * @return array - */ - public function delete($taskId, $checklistItemId) - { - $result = $this->client->call('task.checklistitem.delete', array($taskId, $checklistItemId)); - return $result; - } - - /** - * Marks a check list element as completed. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/complete.php - * @param $taskId integer Task identifier. Required parameter. - * @param $checklistItemId integer Check list element identifier. Required parameter. - * @return array - */ - public function complete($taskId, $checklistItemId) - { - $result = $this->client->call('task.checklistitem.complete', array($taskId, $checklistItemId)); - return $result; - } - - /** - * Marks a check list element as active again. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/renew.php - * @param $taskId integer Task identifier. Required parameter. - * @param $checklistItemId integer Check list element identifier. Required parameter. - * @return array - */ - public function renew($taskId, $checklistItemId) - { - $result = $this->client->call('task.checklistitem.renew', array($taskId, $checklistItemId)); - return $result; - } - - /** - * Moves a check list element and places it in the list after the indicated one. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/moveafteritem.php - * @param $taskId integer Task identifier. Required parameter. - * @param $checklistItemId integer Check list element identifier. Required parameter. - * @param $checklistAfterItemId integer Check list element identifier, after which the given element will be placed. Required parameter. - * @return array - */ - public function moveAfterItem($taskId, $checklistItemId, $checklistAfterItemId) - { - $result = $this->client->call('task.checklistitem.moveafteritem', array($taskId, $checklistItemId, $checklistAfterItemId)); - return $result; - } - - /** - * Checks whether the action is permitted. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/isactionallowed.php - * @param $taskId integer Task identifier. Required parameter. - * @param $checklistItemId integer Comment identifier. Required parameter. - * @param $actionId integer Identifier of the action to be checked: - * 1 - ACTION_ADD; - * 2 - ACTION_MODIFY; - * 3 - ACTION_REMOVE; - * 4 - ACTION_TOGGLE. - * Required parameter. - * @return array - */ - public function isActionAllowed($taskId, $checklistItemId, $actionId) - { - $result = $this->client->call('task.checklistitem.isactionallowed', array($taskId, $checklistItemId, $actionId)); - return $result; - } -} \ No newline at end of file diff --git a/src/classes/task/commentitem.php b/src/classes/task/commentitem.php deleted file mode 100644 index b16b123d..00000000 --- a/src/classes/task/commentitem.php +++ /dev/null @@ -1,120 +0,0 @@ -client->call('task.commentitem.getmanifest'); - return $result; - } - - /** - * Returns the list of comments to a task. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/commentitem/getlist.php - * @param $taskId integer - * @param $order array - * @param $filter array - * @return array - */ - public function getList($taskId, $order, $filter) - { - $result = $this->client->call('task.commentitem.getmanifest', - array( - 'TASKID' => $taskId, - 'ORDER' => $order, - 'FILTER'=> $filter - )); - return $result; - } - - /** - * Returns comments to a task. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/commentitem/get.php - * @param $taskId integer Task identifier. Required parameter. - * @param $commentItemId integer Comment identifier. Required parameter. - * @return array - */ - public function get($taskId, $commentItemId) - { - $result = $this->client->call('task.commentitem.get', - array( - 'TASKID' => $taskId, - 'ITEMID' => $commentItemId - )); - return $result; - } - - /** - * Creates a new comment to a task. Returns the identifier to the comment added. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/commentitem/add.php - * @param $taskId integer Task identifier. Required parameter. - * @param $fields array Data field array for a task (POST_MESSAGE). Required parameter. - * @return array - */ - public function add($taskId, $fields) - { - $result = $this->client->call('task.commentitem.add', - array( - 'TASKID' => $taskId, - 'arFields' => $fields - )); - return $result; - } - - /** - * Updates the comment data. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/commentitem/update.php - * @param $taskId integer Task identifier. Required parameter. - * @param $commentItemId integer Comment identifier. Required parameter. - * @param $fields array Data field array for a task (POST_MESSAGE). Required parameter. - * @return array - */ - public function update($taskId, $commentItemId, $fields) - { - $result = $this->client->call('task.commentitem.add', array($taskId, $commentItemId, array($fields))); - return $result; - } - - /** - * Delete a comment. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/commentitem/delete.php - * @param $taskId integer Task identifier. Required parameter. - * @param $commentItemId integer Comment identifier. Required parameter. - * @return array - */ - public function delete($taskId, $commentItemId) - { - $result = $this->client->call('task.commentitem.add', array($taskId, $commentItemId)); - return $result; - } - - /** - * Checks if the action is permitted. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/isactionallowed.php - * @param $taskId integer Task identifier. Required parameter. - * @param $commentItemId integer Comment identifier. Required parameter. - * @param $actionId integer Identifier of the action to be checked: - * 1 - ACTION_COMMENT_ADD; - * 2 - ACTION_COMMENT_MODIFY; - * 3 - ACTION_COMMENT_REMOVE. - Required parameter. - * @return array - */ - public function isActionAllowed($taskId, $commentItemId, $actionId) - { - $result = $this->client->call('task.commentitem.isactionallowed', array($taskId, $commentItemId, $actionId)); - return $result; - } -} diff --git a/src/classes/task/elapseditem.php b/src/classes/task/elapseditem.php deleted file mode 100644 index 9d237ff9..00000000 --- a/src/classes/task/elapseditem.php +++ /dev/null @@ -1,141 +0,0 @@ -client->call('task.elapseditem.getmanifest'); - return $result; - } - - /** - * Returns a list of entries about elapsed time for a task. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/checklistitem/getlist.php - * @param $taskId integer Task identifier. Required parameter. - * @param $order array Array for result sorting. Sorting field may take the following values: - * ID � identifier of the entry about elapsed time; - * USER_ID � identifier of the user on whose behalf the entry about the elapsed time was made; - * MINUTES � elapsed time, minutes; - * SECONDS � elapsed time, seconds ; - * CREATED_DATE � entry creation date; - * DATE_START � start date; - * DATE_STOP � end date. - * Sorting direction can take the following values: - * asc � ascending; - * desc � descending; - * Optional. By default it is filtered by descending of the entry elapsed time identifier. - * @param $filter array Array of the time {"filtered_field": "filter value" [, ...]}. Filtered field can take the following values: - * ID � comment identifier; - * USER_ID � identifier of the user on whose behalf the entry about the elapsed time was made; - * CREATED_DATE � entry creation date. - * Filtration type may be indicated before the name of the field to be filtered: - * "!" � not equal; - * "<" � less; - * "<=" � less or equal; - * ">" � more; - * ">=" � more or equal. - * filter values - a single value or an array. - * Optional. By default entries are not filtered. - * @return array - */ - public function getList($taskId, $order, $filter) - { - $result = $this->client->call('task.elapseditem.getlist', - array( - 'TASKID' => $taskId, - 'ORDER' => $order, - 'FILTER' => $filter - )); - return $result; - } - - /** - * Returns an entry about elapsed time by its identifier. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/elapseditem/get.php - * @param $taskId integer Task identifier. Required parameter. - * @param $elapsedItemId integer Entry identifier. Required parameter. - * @return array - */ - public function get($taskId, $elapsedItemId) - { - $result = $this->client->call('task.checklistitem.get', - array( - 'TASKID' => $taskId, - 'ITEMID' => $elapsedItemId - )); - return $result; - } - - /** - * Add time spent to the task. Return added record ID. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/elapseditem/add.php - * @param $taskId integer Task identifier. Required parameter. - * @param $fields array Array of time records and comments (SECONDS and COMMENT_TEXT). MINUTES may be used instead of SECONDS, but they may not be used at the same time. - * @return array - */ - public function add($taskId, $fields) - { - $result = $this->client->call('task.elapseditem.add', array($taskId, $fields)); - return $result; - } - - /** - * Change parameters of the specified time spent record. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/elapseditem/update.php - * @param $taskId integer Task identifier. Required parameter. - * @param $elapsedItemId integer Entry identifier. Required parameter. - * @param $fields array Array of time records and comments (SECONDS and COMMENT_TEXT). MINUTES may be used instead of SECONDS, but they may not be used at the same time. - * @return array - */ - public function update($taskId, $elapsedItemId, $fields) - { - $result = $this->client->call('task.elapseditem.update', array($taskId, $elapsedItemId, array($fields))); - return $result; - } - - /** - * Delete time spent record. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/elapseditem/delete.php - * @param $taskId integer Task identifier. Required parameter. - * @param $elapsedItemId integer Time spent record ID. - * @return array - */ - public function delete($taskId, $elapsedItemId) - { - $result = $this->client->call('task.elapseditem.delete', array($taskId, $elapsedItemId)); - return $result; - } - - /** - * Verify whether the action is allowed. - * @see http://www.bitrixsoft.com/rest_help/tasks/task/elapseditem/isactionallowed.php - * @param $taskId integer Task identifier. Required parameter. - * @param $elapsedItemId integer Time spent record ID. - * @param $actionId integer Identifier of the action to be checked: - * Action ID: - * 1 - ACTION_ELAPSED_TIME_ADD; - * 2 - ACTION_ELAPSED_TIME_MODIFY; - * 3 - ACTION_ELAPSED_TIME_REMOVE. - * Required parameter. - * @return array - */ - public function isActionAllowed($taskId, $elapsedItemId, $actionId) - { - $result = $this->client->call('task.elapseditem.isActionAllowed', array($taskId, $elapsedItemId, $actionId)); - return $result; - } -} \ No newline at end of file diff --git a/src/classes/task/item.php b/src/classes/task/item.php deleted file mode 100644 index 9b7a2e6b..00000000 --- a/src/classes/task/item.php +++ /dev/null @@ -1,237 +0,0 @@ -client->call('task.item.getmanifest'); - return $result; - } - - /** - * add new task - * @link http://dev.1c-bitrix.ru/rest_help/tasks/task/item/add.php - * @link http://dev.1c-bitrix.ru/rest_help/tasks/fields.php - * @param array $taskData - * @return array new task ID - * @throws Bitrix24Exception - */ - public function add($taskData) - { - $result = $this->client->call('task.item.add', array($taskData)); - return $result; - } - - /** - * Return array of task data fields (TITLE, DESCRIPTION, etc.) - * @param $taskId - * @return array - * @throws Bitrix24Exception - * @throws \Bitrix24\Bitrix24SecurityException - */ - public function getData($taskId) - { - $result = $this->client->call('task.item.getdata', array($taskId)); - return $result; - } - - /** - * Update task data. The following fields may be updated. Business logic and permissions are taken into account when updating task data. - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/update.php - * @param $taskId integer Task ID. - * @param $taskData array List of updated fields. - * @return array - * - */ - public function update($taskId, $taskData) - { - $result = $this->client->call('task.item.update', array($taskId, $taskData)); - return $result; - } - - /** - * Delete task. - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/delete.php - * @param $taskId integer Task ID. - * @return array - */ - public function delete($taskId) - { - $result = $this->client->call('task.item.delete', array($taskId)); - return $result; - } - - /** - * Return task description. - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/getdescription.php - * @param $taskId integer Task ID. - * @param $format integer 1 (Corresponds to the PHP constant CTaskItem::DESCR_FORMAT_RAW) � - * description will be returned in the format it is stored in the database (HTML or BB-code), will not be sanitized; - * 2 (Corresponds to the PHP constant CTaskItem::DESCR_FORMAT_HTML) � description will be returned in HTML, will first be sanitized (if included in task module settings); - * 3 (Corresponds to the PHP constant CTaskItem::DESCR_FORMAT_PLAIN_TEXT) � description will be returned as plain text (no HTML tags). - * @return array - */ - public function getDescription($taskId, $format) - { - $result = $this->client->call('task.item.getdescription', $taskId, $format); - return $result; - } - - /** - * Return array of links to files attached to the task. - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/getfiles.php - * @param $taskId integer Task ID. - * @return array - */ - public function getFiles($taskId) - { - $result = $this->client->call('task.item.getfiles', array($taskId)); - return $result; - } - - /** - * Return array with parent task IDs - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/getdependson.php - * @param $taskId integer Task ID. - * @return array - */ - public function getDependSon($taskId) - { - $result = $this->client->call('task.item.getdependson', array($taskId)); - return $result; - } - - /** - * Return array of allowed task actions IDs (see PHP class constants CTaskItem). - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/getallowedactions.php - * @param $taskId integer Task ID. - * @return array - */ - public function getAllowedActions($taskId) - { - $result = $this->client->call('task.item.getallowedactions', array($taskId)); - return $result; - } - - /** - * Return an array whose keys are acton names (the names correspond to PHP class constants CTaskItem) and values show whether the action is allowed (true) or not allowed (false). - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/getallowedtaskactionsasstrings.php - * @param $taskId integer Task ID. - * @return array - */ - public function getAllowedTaskActionsAsStrings($taskId) - { - $result = $this->client->call('task.item.getallowedtaskactionsasstrings', array($taskId)); - return $result; - } - - /** - * Return true if action is allowed, else returns false. - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/isactionallowed.php - * @param $taskId integer Task ID. - * @param $actionId integer Validated action ID (see CTaskItem::ACTION_* constants of PHP class CTaskItem). - * @return array - */ - public function isActionAllowed($taskId, $actionId) - { - $result = $this->client->call('task.item.isactionallowed', array($taskId), array($actionId)); - return $result; - } - - /** - * Delegate task to a user. - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/delegate.php - * @param $taskId integer Task ID - * @param $userId integer New responsible person ID - * @return array - */ - public function delegate($taskId, $userId) - { - $result = $this->client->call('task.item.delegate', array($taskId), array($userId)); - return $result; - } - - /** - * Change task status to In Progress - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/startexecution.php - * @param $taskId integer Task ID - * @return array - */ - public function startExecution($taskId) - { - $result = $this->client->call('task.item.startexecution', array($taskId)); - return $result; - } - - /** - * Change task status to Deferred - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/defer.php - * @param $taskId integer Task ID - * @return array - */ - public function defer($taskId) - { - $result = $this->client->call('task.item.defer', array($taskId)); - return $result; - } - - /** - * Change status to Completed or Supposedly completed (requires creator's attention). - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/complete.php - * @param $taskId integer Task ID - * @return array - */ - public function complete($taskId) - { - $result = $this->client->call('task.item.complete', array($taskId)); - return $result; - } - - /** - * Change status to Pending. - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/renew.php - * @param $taskId integer Task ID - * @return array - */ - public function renew($taskId) - { - $result = $this->client->call('task.item.renew', array($taskId)); - return $result; - } - - /** - * Change status of task waiting for confirmation to Completed. - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/approve.php - * @param $taskId integer Task ID - * @return array - */ - public function approve($taskId) - { - $result = $this->client->call('task.item.approve', array($taskId)); - return $result; - } - - /** - * Change status of task waiting for confirmation to Pending. - * @link http://www.bitrixsoft.com/rest_help/tasks/task/item/disapprove.php - * @param $taskId integer Task ID - * @return array - */ - public function disapprove($taskId) - { - $result = $this->client->call('task.item.disapprove', array($taskId)); - return $result; - } -} \ No newline at end of file diff --git a/src/classes/task/items.php b/src/classes/task/items.php deleted file mode 100644 index fe057ccc..00000000 --- a/src/classes/task/items.php +++ /dev/null @@ -1,34 +0,0 @@ -client->call( - 'task.items.getlist', - array( - 'ORDER' => $ORDER, - 'FILTER'=> $FILTER, - 'TASKDATA'=> $TASKDATA, - array('NAV_PARAMS'=> $NAV_PARAMS) - ) - ); - return $fullResult; - } -} \ No newline at end of file diff --git a/src/classes/task/planner.php b/src/classes/task/planner.php deleted file mode 100644 index 0f42610a..00000000 --- a/src/classes/task/planner.php +++ /dev/null @@ -1,20 +0,0 @@ -client->call('task.planner.getlist'); - return $fullResult; - } -} \ No newline at end of file diff --git a/src/classes/user/user.php b/src/classes/user/user.php deleted file mode 100644 index c9be1b37..00000000 --- a/src/classes/user/user.php +++ /dev/null @@ -1,82 +0,0 @@ -client->call('user.admin'); - return $result['result']; - } - - /** - * Get information about current user by his auth information. This method will be use security sign automatically - * @link http://dev.1c-bitrix.ru/rest_help/users/user_current.php - * @throws Bitrix24Exception - * @return array - */ - public function current() - { - $result = $this->client->call('user.current', array('state' => $this->client->getSecuritySignSalt())); - return $result; - } - - /** - * Get list of fields entity user - * @link http://dev.1c-bitrix.ru/rest_help/users/user_fields.php - * @throws Bitrix24Exception - * @return array - */ - public function fields() - { - $result = $this->client->call('user.fields'); - return $result; - } - - /** - * Get list of users - * @link http://dev.1c-bitrix.ru/rest_help/users/user_get.php - * @throws Bitrix24Exception - * @param $SORT - field name to sort by them - * @param $ORDER - sort direction? must be set to ASC or DESC - * @param $FILTER - list of fields user entity to filter result - * @return array - */ - public function get($SORT, $ORDER, $FILTER) - { - $result = $this->client->call('user.get', - array( - 'SORT' => $SORT, - 'ORDER' => $ORDER, - 'FILTER'=> $FILTER) - ); - return $result; - } - - - /** - * Check if current user has any of access rights specified by $access param - * @link http://dev.1c-bitrix.ru/rest_help/general/user_access.php - * @throws Bitrix24Exception - * @param array $access - list of access rights to check - * @return array - */ - public function access($access) - { - $result = $this->client->call('user.access', - array( - 'ACCESS' => $access - ) - ); - return $result; - } -} - diff --git a/src/contracts/ibitrix24.php b/src/contracts/ibitrix24.php deleted file mode 100644 index c328223f..00000000 --- a/src/contracts/ibitrix24.php +++ /dev/null @@ -1,364 +0,0 @@ - value1, CURLOPT_XXX2 => value2,...) - * @return bool - */ - public function setCustomCurlOptions($options); - - /** - * Return raw request, contain all cURL options array and API query. Data available after you try to call method call - * numbers of array keys is const of cURL module. Example: CURLOPT_RETURNTRANSFER = 19913 - * @return array | null - */ - public function getRawRequest(); - - /** - * Return result from function curl_getinfo. Data available after you try to call method call - * @return array | null - */ - public function getRequestInfo(); - - /** - * Return additional parameters of last api-call. Data available after you try to call method call - * @return array | null - */ - public function getMethodParameters(); - - /** - * Execute Bitrix24 REST API method - * - * @param string $methodName - * @param array $additionalParameters - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * @throws Bitrix24SecurityException - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24PortalRenamedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * - * @return array - */ - public function call($methodName, array $additionalParameters = array()); - - /** - * Get raw response from Bitrix24 before json_decode call, method available only in debug mode. - * To activate debug mode you must before set to true flag isSaveRawResponse in class construct - * @throws Bitrix24Exception - * @return string - */ - public function getRawResponse(); - - /** - * Get new access token - * - * @return array - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24PortalRenamedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * - */ - public function getNewAccessToken(); - - /** - * Authorize and get first access token - * - * @param $code - * - * @return array - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24PortalRenamedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * - */ - public function getFirstAccessToken($code); - - /** - * Check is access token expire, call list of all available api-methods from B24 portal with current access token - * if we have an error code expired_token then return true else return false - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24PortalRenamedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * - * @return boolean - */ - public function isAccessTokenExpire(); - - /** - * Get list of all methods available for current application - * @param array | null $applicationScope - * @param bool $isFull - * @return array - * @throws Bitrix24Exception - */ - public function getAvailableMethods(array $applicationScope = array(), $isFull = false); - - /** - * get list of scope for current application from bitrix24 api - * @param bool $isFull - * @throws Bitrix24Exception - * @return array - */ - public function getScope($isFull = false); - - /** - * set CURL request count retries - * @param $retriesCnt - * @return boolean - */ - public function setRetriesToConnectCount($retriesCnt = 1); - - /** - * set retries to connect timeout in microseconds - * @param $microseconds - * @return boolean - */ - public function setRetriesToConnectTimeout($microseconds = 1000000); - - /** - * get CURL request count retries - * @return int - */ - public function getRetriesToConnectCount(); - - /** - * get retries to connect timeout in microseconds - * @return mixed - */ - public function getRetriesToConnectTimeout(); - - /** - * Add call to batch. If [[$callback]] parameter is set, it will receive call result as first parameter. - * - * @param string $method - * @param array $parameters - * @param callable|null $callback - * - * @return string Unique call ID. - */ - public function addBatchCall($method, array $parameters = array(), callable $callback = null); - - /** - * Process batch calls. - * - * @param int $halt Halt batch on error - * @param int $delay Delay between batch calls (in msec) - * - * @throws Bitrix24Exception - * @throws Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - */ - public function processBatchCalls($halt = 0, $delay = self::BATCH_DELAY); - - /** - * Return true, if we have unprocessed batch calls. - * - * @return bool - */ - public function hasBatchCalls(); -} \ No newline at end of file diff --git a/src/exceptions/bitrix24apiexception.php b/src/exceptions/bitrix24apiexception.php deleted file mode 100644 index 04c2b405..00000000 --- a/src/exceptions/bitrix24apiexception.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Exceptions; - -/** - * Class Bitrix24PaymentRequiredException - * @package Bitrix24 - */ -class Bitrix24ApiException extends Bitrix24Exception -{ -} \ No newline at end of file diff --git a/src/exceptions/bitrix24badgatewayexception.php b/src/exceptions/bitrix24badgatewayexception.php deleted file mode 100644 index 7094504f..00000000 --- a/src/exceptions/bitrix24badgatewayexception.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Exceptions; - -/** - * Class Bitrix24BadGatewayException - * @package Bitrix24 - */ -class Bitrix24BadGatewayException extends Bitrix24IoException -{ -} \ No newline at end of file diff --git a/src/exceptions/bitrix24emptyresponseexception.php b/src/exceptions/bitrix24emptyresponseexception.php deleted file mode 100644 index 1342d227..00000000 --- a/src/exceptions/bitrix24emptyresponseexception.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Exceptions; - -/** - * Class Bitrix24IOException - * @package Bitrix24 - */ -class Bitrix24EmptyResponseException extends Bitrix24IoException -{ -} \ No newline at end of file diff --git a/src/exceptions/bitrix24exception.php b/src/exceptions/bitrix24exception.php deleted file mode 100644 index 68f6f75a..00000000 --- a/src/exceptions/bitrix24exception.php +++ /dev/null @@ -1,33 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Exceptions; - -/** - * Class Bitrix24Exception - * - * \Exception - * \Bitrix24Exception — base class - * \Bitrix24IoException — I/O network errors - * \Bitrix24EmptyResponseException — empty response from Bitrix24 portal - * \Bitrix24ApiException — API level errors - * \Bitrix24WrongClientException — Wrong client or application will be deleted from portal - * \Bitrix24MethodNotFoundException — API-method not found - * \Bitrix24TokenIsInvalidException — The access token provided is invalid - * \Bitrix24TokenIsExpiredException — The access token provided has expired - * \Bitrix24PortalDeletedException — Bitrix24 portal deleted - * \Bitrix24PortalRenamedException — Bitrix24 portal renamed - * \Bitrix24PaymentRequiredException — Bitrix24 application payment required - * \Bitrix24SecurityException — Security errors for protected methods - * - * @package Bitrix24\Exceptions - */ -class Bitrix24Exception extends \Exception -{ -} \ No newline at end of file diff --git a/src/exceptions/bitrix24ioexception.php b/src/exceptions/bitrix24ioexception.php deleted file mode 100644 index 5817969b..00000000 --- a/src/exceptions/bitrix24ioexception.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Exceptions; - -/** - * Class Bitrix24IoException - * @package Bitrix24 - */ -class Bitrix24IoException extends Bitrix24Exception -{ -} \ No newline at end of file diff --git a/src/exceptions/bitrix24methodnotfoundexception.php b/src/exceptions/bitrix24methodnotfoundexception.php deleted file mode 100644 index 78116a25..00000000 --- a/src/exceptions/bitrix24methodnotfoundexception.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Exceptions; - -/** - * Class Bitrix24WrongClientException - * @package Bitrix24 - */ -class Bitrix24MethodNotFoundException extends Bitrix24ApiException -{ -} \ No newline at end of file diff --git a/src/exceptions/bitrix24paymentrequiredexception.php b/src/exceptions/bitrix24paymentrequiredexception.php deleted file mode 100644 index dce1d1a0..00000000 --- a/src/exceptions/bitrix24paymentrequiredexception.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Exceptions; - -/** - * Class Bitrix24PaymentRequiredException - * @package Bitrix24 - */ -class Bitrix24PaymentRequiredException extends Bitrix24ApiException -{ -} \ No newline at end of file diff --git a/src/exceptions/bitrix24portaldeletedexception.php b/src/exceptions/bitrix24portaldeletedexception.php deleted file mode 100644 index 9001a5cc..00000000 --- a/src/exceptions/bitrix24portaldeletedexception.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Exceptions; - -/** - * Class Bitrix24PortalDeletedException - * @package Bitrix24 - */ -class Bitrix24PortalDeletedException extends Bitrix24ApiException -{ -} \ No newline at end of file diff --git a/src/exceptions/bitrix24portalrenamedexception.php b/src/exceptions/bitrix24portalrenamedexception.php deleted file mode 100644 index 6656f52d..00000000 --- a/src/exceptions/bitrix24portalrenamedexception.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Exceptions; - -/** - * Class Bitrix24PortalRenamedException - * @package Bitrix24 - */ -class Bitrix24PortalRenamedException extends Bitrix24ApiException -{ -} \ No newline at end of file diff --git a/src/exceptions/bitrix24securityexception.php b/src/exceptions/bitrix24securityexception.php deleted file mode 100644 index aeda62ce..00000000 --- a/src/exceptions/bitrix24securityexception.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Exceptions; - -/** - * Class Bitrix24SecurityException - * @package Bitrix24 - */ -class Bitrix24SecurityException extends Bitrix24Exception -{ -} \ No newline at end of file diff --git a/src/exceptions/bitrix24tokenisexpiredexception.php b/src/exceptions/bitrix24tokenisexpiredexception.php deleted file mode 100644 index 9c6fa130..00000000 --- a/src/exceptions/bitrix24tokenisexpiredexception.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Exceptions; - -/** - * Class Bitrix24TokenIsExpiredException - * @package Bitrix24 - */ -class Bitrix24TokenIsExpiredException extends Bitrix24ApiException -{ -} \ No newline at end of file diff --git a/src/exceptions/bitrix24tokenisinvalidexception.php b/src/exceptions/bitrix24tokenisinvalidexception.php deleted file mode 100644 index 28c18571..00000000 --- a/src/exceptions/bitrix24tokenisinvalidexception.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Exceptions; - -/** - * Class Bitrix24TokenIsInvalidException - * @package Bitrix24 - */ -class Bitrix24TokenIsInvalidException extends Bitrix24ApiException -{ -} \ No newline at end of file diff --git a/src/exceptions/bitrix24wrongclientexception.php b/src/exceptions/bitrix24wrongclientexception.php deleted file mode 100644 index 92c280a9..00000000 --- a/src/exceptions/bitrix24wrongclientexception.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Exceptions; - -/** - * Class Bitrix24WrongClientException - * @package Bitrix24 - */ -class Bitrix24WrongClientException extends Bitrix24ApiException -{ -} \ No newline at end of file diff --git a/src/presets/app/app.php b/src/presets/app/app.php deleted file mode 100644 index 05282d5b..00000000 --- a/src/presets/app/app.php +++ /dev/null @@ -1,85 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Presets\Event; - -/** - * Class Event - * @package Bitrix24\Presets\Event - */ -class Event -{ - /** - * @var string event code when bitrix24 application has uninstall - */ - const ON_APP_UNINSTALL = 'ONAPPUNINSTALL'; - /** - * @var string event code when bitrix24 application install - */ - const ON_APP_INSTALL = 'ONAPPINSTALL'; - /** - * @var string event code when bitrix24 application update - */ - const ON_APP_UPDATE = 'ONAPPUPDATE'; - /** - * @var string event code when bitrix24 application payment - */ - const ON_APP_PAYMENT = 'ONAPPPAYMENT'; - /** - * @var string - */ - const ON_APP_TEST = 'ONAPPTEST'; - /** - * @var string event code when task add in bitrix24 - */ - const ON_TASK_ADD = 'ONTASKADD'; - /** - * @var string - */ - const ON_VOXIMPLANT_CALL_INIT = 'ONVOXIMPLANTCALLINIT'; - /** - * @var string - */ - const ON_VOXIMPLANT_CALL_START = 'ONVOXIMPLANTCALLSTART'; - /** - * @var string - */ - const ON_VOXIMPLANT_CALL_END = 'ONVOXIMPLANTCALLEND'; - /** - * @var string event code when task in bitrix24 has update - */ - const ON_TASK_UPDATE = 'ONTASKUPDATE'; - /** - * @var string event code when task in bitrix24 has delete - */ - const ON_TASK_DELETE = 'ONTASKDELETE'; - /** - * @var string - */ - const ON_TASK_COMMENT_ADD = 'ONTASKCOMMENTADD'; - /** - * @var string - */ - const ON_TASK_COMMENT_UPDATE = 'ONTASKCOMMENTUPDATE'; - /** - * @var string - */ - const ON_TASK_COMMENT_DELETE = 'ONTASKCOMMENTDELETE'; - /** - * @var string event code when new user in bitrix24 has added - */ - const ON_USER_ADD = 'ONUSERADD'; - /** - * @var string - */ - const ON_CRM_LEAD_ADD = 'ONCRMLEADADD'; - /** - * @var string - */ - const ON_CRM_LEAD_UPDATE = 'ONCRMLEADUPDATE'; - /** - * @var string - */ - const ON_CRM_LEAD_DELETE = 'ONCRMLEADDELETE'; - /** - * @var string - */ - const ON_CRM_DEAL_ADD = 'ONCRMDEALADD'; - /** - * @var string - */ - const ON_CRM_DEAL_UPDATE = 'ONCRMDEALUPDATE'; - /** - * @var string - */ - const ON_CRM_DEAL_DELETE = 'ONCRMDEALDELETE'; - /** - * @var string - */ - const ON_CRM_COMPANY_ADD = 'ONCRMCOMPANYADD'; - /** - * @var string - */ - const ON_CRM_COMPANY_UPDATE = 'ONCRMCOMPANYUPDATE'; - /** - * @var string - */ - const ON_CRM_COMPANY_DELETE = 'ONCRMCOMPANYDELETE'; - /** - * @var string - */ - const ON_CRM_CONTACT_ADD = 'ONCRMCONTACTADD'; - /** - * @var string - */ - const ON_CRM_CONTACT_UPDATE = 'ONCRMCONTACTUPDATE'; - /** - * @var string - */ - const ON_CRM_CONTACT_DELETE = 'ONCRMCONTACTDELETE'; - /** - * @var string - */ - const ON_CRM_CURRENCY_ADD = 'ONCRMCURRENCYADD'; - /** - * @var string - */ - const ON_CRM_CURRENCY_UPDATE = 'ONCRMCURRENCYUPDATE'; - /** - * @var string - */ - const ON_CRM_CURRENCY_DELETE = 'ONCRMCURRENCYDELETE'; - /** - * @var string - */ - const ON_CRM_PRODUCT_ADD = 'ONCRMPRODUCTADD'; - /** - * @var string - */ - const ON_CRM_PRODUCT_UPDATE = 'ONCRMPRODUCTUPDATE'; - /** - * @var string - */ - const ON_CRM_PRODUCT_DELETE = 'ONCRMPRODUCTDELETE'; - /** - * @var string - */ - const ON_CRM_ACTIVITY_ADD = 'ONCRMACTIVITYADD'; - /** - * @var string - */ - const ON_CRM_ACTIVITY_UPDATE = 'ONCRMACTIVITYUPDATE'; - /** - * @var string - */ - const ON_CRM_ACTIVITY_DELETE = 'ONCRMACTIVITYDELETE'; - /** - * @var string - */ - const ON_CRM_QUOTE_ADD = 'ONCRMQUOTEADD'; - /** - * @var string - */ - const ON_CRM_QUOTE_UPDATE = 'ONCRMQUOTEUPDATE'; - /** - * @var string - */ - const ON_CRM_QUOTE_DELETE = 'ONCRMQUOTEDELETE'; - /** - * @var string event on bot add to chat or private chat - */ - const ON_IM_BOT_JOIN_CHAT = 'ONIMBOTJOINCHAT'; - /** - * @var string event on bot delete - */ - const ON_IM_BOT_DELETE = 'ONIMBOTDELETE'; - /** - * @var string event on bot gets message - */ - const ON_IM_BOT_MESSAGE_ADD = 'ONIMBOTMESSAGEADD'; - /** - * @var string event on bot gets command - */ - const ON_IM_COMMAND_ADD = 'ONIMCOMMANDADD'; -} diff --git a/src/presets/event/fields.php b/src/presets/event/fields.php deleted file mode 100644 index cf7056b9..00000000 --- a/src/presets/event/fields.php +++ /dev/null @@ -1,29 +0,0 @@ - and contributors - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24\Presets\Im; - -/** - * Interface iChatColor - * @package Bitrix24\Presets\Im - */ -interface iChatColor -{ - /** - * @var string chat color in mobile - */ - const RED = '#FF0000'; - /** - * @var string chat color in mobile - */ - const GREEN = '#008000'; - /** - * @var string chat color in mobile - */ - const MINT = '#98ff98'; - /** - * @var string chat color in mobile - */ - const LIGHT_BLUE = '#add8e6'; - /** - * @var string chat color in mobile - */ - const DARK_BLUE = '#00008b'; - /** - * @var string chat color in mobile - */ - const PURPLE = '#800080'; - /** - * @var string chat color in mobile - */ - const AQUA = '#00ffff'; - /** - * @var string chat color in mobile - */ - const PINK = '#ffc0cb'; - /** - * @var string chat color in mobile - */ - const LIME = '#bfff00'; - /** - * @var string chat color in mobile - */ - const BROWN = '#a52a2a'; - /** - * @var string chat color in mobile - */ - const AZURE = '#007fff'; - /** - * @var string chat color in mobile - */ - const KHAKI = '#c3b091'; - /** - * @var string chat color in mobile - */ - const SAND = '#c2b280'; - /** - * @var string chat color in mobile - */ - const MARENGO = '#4C5866'; - /** - * @var string chat color in mobile - */ - const GRAY = '#808080'; - /** - * @var string chat color in mobile - */ - const GRAPHITE = '#383428'; -} \ No newline at end of file diff --git a/src/presets/lang.php b/src/presets/lang.php deleted file mode 100644 index 991c5b0f..00000000 --- a/src/presets/lang.php +++ /dev/null @@ -1,41 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\Presets; - -/** - * Class Scope - * @package Bitrix24\Presets - */ -class Scope -{ - /** - * @var string work with business process - */ - const BIZPROC = 'bizproc'; - - /** - * @var string work with calendar - */ - const CALENDAR = 'calendar'; - - /** - * @var string work with CRM - */ - const CRM = 'crm'; - - /** - * @var string work with bitrix24 disk - */ - const DISK = 'disk'; - - /** - * @var string work with departments - */ - const DEPARTMENT = 'department'; - - /** - * @var string work with B24 entity - */ - const ENTITY = 'entity'; - - /** - * @var string work with IM - */ - const IM = 'im'; - - /** - * @var string work with IM bot - */ - const IMBOT = 'imbot'; - - /** - * @var string work with users - */ - const USER = 'user'; - - /** - * @var string work with mail - */ - const MAILSERVICE = 'mailservice'; - - /** - * @var string work with task - */ - const TASK = 'task'; - - /** - * @var string work with task extended - */ - const TASKS_EXTENDED = 'tasks_extended'; - - /** - * @var string work with telephony - */ - const TELEPHONY = 'telephony'; - - /** - * @var string work with life line - */ - const LOG = 'log'; - - /** - * @var string work with sonet group - */ - const SONET_GROUP = 'sonet_group'; - - /** - * @var string work with lists - */ - const LISTS = 'lists'; - - /** - * @var string work with placement - */ - const PLACEMENT = 'placement'; -} \ No newline at end of file diff --git a/src/presets/task/item/fields.php b/src/presets/task/item/fields.php deleted file mode 100644 index a46e720d..00000000 --- a/src/presets/task/item/fields.php +++ /dev/null @@ -1,216 +0,0 @@ -getTags() will return an array of the tag names. - */ - const TAGS ='TAGS'; - /** - * @var string A boolean (Y/N) value which, if set to "Y", specifies that a responsible person associated with the task is allowed to shift the deadline date. Read, write - */ - const ALLOW_CHANGE_DEADLINE = 'ALLOW_CHANGE_DEADLINE'; - /** - * @var string A boolean (Y/N) value which, if set to "Y", specifies that the task result needs to be approved by a creator. Otherwise, the task will auto close once marked as completed. Read, write - */ - const TASK_CONTROL = 'TASK_CONTROL'; - /** - * @var string Specifies the ID of a parent task. Read, write - */ - const PARENT_ID = 'PARENT_ID'; - /** - * @var string Specifies the ID of a task that needs to be completed prior to this one. Read, write - */ - const DEPENDS_ON = 'DEPENDS_ON'; - /** - * @var string Specifies the ID of a workgroup to which this task relates. Read, write - */ - const GROUP_ID = 'GROUP_ID'; - /** - * @var string The user ID of a person to whom the task is assigned. Read, write - */ - const RESPONSIBLE_ID = 'RESPONSIBLE_ID'; - /** - * @var string Specifies a time estimate for the task. Read, write - */ - const TIME_ESTIMATE = 'TIME_ESTIMATE'; - /** - * @var integer The current task ID. The identifier is unique across the database. Read - */ - const ID = 'ID'; - /** - * @var integer Specifies the user ID of a person who created the task. Read, write - */ - const CREATED_BY = 'CREATED_BY'; - /** - * @var string A boolean (Y/N) value which, if set to "Y", specifies that the task description includes BB codes. Read - */ - const DESCRIPTION_IN_BBCODE = 'DESCRIPTION_IN_BBCODE'; - /** - * @var string A text description of the reason for rejecting the task. Read, write - */ - const DECLINE_REASON = 'DECLINE_REASON'; - /** - * @var string Determines the task's real status set using the STATUS field (see CTasks::STATE_xxx). This field is read-only. - */ - const REAL_STATUS = 'REAL_STATUS'; - /** - * @var string Use this field to set the meta status for a task. Read, write - * To set this field, use the CTasks::STATE_xxx constants. However, this field may return one of the CTasks::METASTATE_xxx values. - * For example, if a task had never been started and became overdue, this field will return CTasks::METASTATE_EXPIRED, - * while the real status is CTasks::STATE_NEW returned by the REAL_STATUS field. - */ - const STATUS = 'STATUS'; - /** - * @var string Contains the first name of a person to whom the task is assigned (a responsible person). Read - */ - const RESPONSIBLE_NAME = 'RESPONSIBLE_NAME'; - /** - * @var string The last name of the task's responsible person. Read - */ - const RESPONSIBLE_LAST_NAME = 'RESPONSIBLE_LAST_NAME'; - /** - * @var string The second name of the task's responsible person. Read - */ - const RESPONSIBLE_SECOND_NAME = 'RESPONSIBLE_SECOND_NAME'; - /** - * @var \DateTime Specifies the date the task was started. Read - */ - const DATE_START = 'DATE_START'; - /** - * @var string Specifies the time required to complete the task, in minutes. Read - */ - const DURATION_FACT = 'DURATION_FACT'; - /** - * @var string Contains the first name of a person who created the task. Read - */ - const CREATED_BY_NAME = 'CREATED_BY_NAME'; - /** - * @var string The last name of the task creator. Read - */ - const CREATED_BY_LAST_NAME = 'CREATED_BY_LAST_NAME'; - /** - * @var string The second name of the task creator. Read - */ - const CREATED_BY_SECOND_NAME = 'CREATED_BY_SECOND_NAME'; - /** - * @var string Specifies the date the task was created. Read - */ - const CREATED_DATE = 'CREATED_DATE'; - /** - * @var string The user ID of a person who last updated the task. Read - */ - const CHANGED_BY = 'CHANGED_BY'; - /** - * @var string Specifies the date the task was last updated. Read - */ - const CHANGED_DATE = 'CHANGED_DATE'; - /** - * @var string The user ID of a person who changed the task status. Read - */ - const STATUS_CHANGED_BY = 'STATUS_CHANGED_BY'; - /** - * @var string Specifies the date the task status was changed. Read - */ - const STATUS_CHANGED_DATE = 'STATUS_CHANGED_DATE'; - /** - * @var string The user ID of a person who completed the task. Read - */ - const CLOSED_BY = 'CLOSED_BY'; - /** - * @var string Specifies the date the task was completed. Read - */ - const CLOSED_DATE = 'CLOSED_DATE'; - /** - * @var string A GUID (globally unique identifier) associated with the task. It can be said, with a fair amount of confidence, - * that this identifier will always remain unique across multiple databases. Read - */ - const GUID = 'GUID'; - /** - * @var string The rating score given by a task creator. Read, write - */ - const MARK ='MARK'; - /** - * @var string Contains the date the task was last viewed in the public area by a currently logged in user. Read - */ - const VIEWED_DATE = 'VIEWED_DATE'; - /** - * @var string Specifies the actual time spent for the task, in seconds. Read - */ - const TIME_SPENT_IN_LOGS = 'TIME_SPENT_IN_LOGS'; - /** - * @var string Specifies the task external ID. Read, write - */ - const XML_ID = 'XML_ID'; - /** - * @var string A boolean (Y/N) value which, if set to "Y", specifies that the system keeps tracking of the time spent for the task. Read, write - */ - const ALLOW_TIME_TRACKING ='ALLOW_TIME_TRACKING'; - /** - * @var string A boolean (Y/N) value which, if set to "Y", includes the task in the performance report. Read, write - */ - const ADD_IN_REPORT = 'ADD_IN_REPORT'; - /** - * @var string Specifies the ID of the forum containing comments to the task. Read, write - */ - const FORUM_ID = 'FORUM_ID'; - /** - * @var string Specifies the ID of the forum topic containing comments to the task. Read, write - */ - const FORUM_TOPIC_ID = 'FORUM_TOPIC_ID'; - /** - * @var string Contains the number of forum comments. Read - */ - const COMMENTS_COUNT ='COMMENTS_COUNT'; - /** - * @var string Specifies the ID of the site on which the task was created. Read, write - */ - const SITE_ID = 'SITE_ID'; - /** - * @var string A boolean (Y/N) value which, if set to "Y", specifies that at least one of the task participants is subordinate to a current user. Read - */ - const SUBORDINATE = 'SUBORDINATE'; - /** - * @var string Contains the ID of a template used to create the task. This field may be empty for tasks created in outdated versions. Read - */ - const FORKED_BY_TEMPLATE_ID = 'FORKED_BY_TEMPLATE_ID'; -} \ No newline at end of file diff --git a/src/presets/uri.php b/src/presets/uri.php deleted file mode 100644 index 97378bb0..00000000 --- a/src/presets/uri.php +++ /dev/null @@ -1,13 +0,0 @@ - value1, CURLOPT_XXX2 => value2,...) - * - * @return bool - */ - public function setCustomCurlOptions($options) - { - } - - /** - * Return raw request, contain all cURL options array and API query. Data available after you try to call method call - * numbers of array keys is const of cURL module. Example: CURLOPT_RETURNTRANSFER = 19913 - * - * @return array | null - */ - public function getRawRequest() - { - } - - /** - * Return result from function curl_getinfo. Data available after you try to call method call - * - * @return array | null - */ - public function getRequestInfo() - { - } - - /** - * Return additional parameters of last api-call. Data available after you try to call method call - * - * @return array | null - */ - public function getMethodParameters() - { - } - - /** - * Execute Bitrix24 REST API method - * - * @param string $methodName - * @param array $additionalParameters - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * @throws Bitrix24SecurityException - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * - * @return array - */ - public function call($methodName, array $additionalParameters = array()) - { - } - - /** - * Get raw response from Bitrix24 before json_decode call, method available only in debug mode. - * To activate debug mode you must before set to true flag isSaveRawResponse in class construct - * - * @throws Bitrix24Exception - * - * @return string - */ - public function getRawResponse() - { - } - - /** - * Get new access token - * - * @return array - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * - */ - public function getNewAccessToken() - { - } - - /** - * Authorize and get first access token - * - * @param $code - * - * @return array - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * - */ - public function getFirstAccessToken($code) - { - } - - /** - * Check is access token expire, call list of all available api-methods from B24 portal with current access token - * if we have an error code expired_token then return true else return false - * - * @throws Bitrix24Exception - * @throws Bitrix24ApiException - * @throws Bitrix24PortalDeletedException - * @throws Bitrix24IoException - * @throws Bitrix24EmptyResponseException - * @throws Bitrix24TokenIsInvalidException - * @throws Bitrix24TokenIsExpiredException - * @throws Bitrix24WrongClientException - * @throws Bitrix24MethodNotFoundException - * @throws Bitrix24PaymentRequiredException - * - * @return boolean - */ - public function isAccessTokenExpire() - { - } - - /** - * Get list of all methods available for current application - * - * @param array | null $applicationScope - * @param bool $isFull - * - * @return array - * - * @throws Bitrix24Exception - */ - public function getAvailableMethods(array $applicationScope = array(), $isFull = false) - { - } - - /** - * get list of scope for current application from bitrix24 api - * - * @param bool $isFull - * - * @throws Bitrix24Exception - * - * @return array - */ - public function getScope($isFull = false) - { - } - - /** - * set CURL request count retries - * - * @param $retriesCnt - * - * @return boolean - */ - public function setRetriesToConnectCount($retriesCnt = 1) - { - } - - /** - * set retries to connect timeout in microseconds - * - * @param $microseconds - * - * @return boolean - */ - public function setRetriesToConnectTimeout($microseconds = 1000000) - { - } - - /** - * get CURL request count retries - * - * @return int - */ - public function getRetriesToConnectCount() - { - } - - /** - * get retries to connect timeout in microseconds - * - * @return mixed - */ - public function getRetriesToConnectTimeout() - { - } - - /** - * Add call to batch. If [[$callback]] parameter is set, it will receive call result as first parameter. - * - * @param string $method - * @param array $parameters - * @param callable|null $callback - * - * @return string Unique call ID. - */ - public function addBatchCall($method, array $parameters = array(), callable $callback = null) - { - } - - /** - * Return true, if we have unprocessed batch calls. - * - * @return bool - */ - public function hasBatchCalls() - { - } - - /** - * Process batch calls. - * - * @param int $halt Halt batch on error - * @param int $delay Delay between batch calls (in msec) - * - * @throws Bitrix24Exception - * @throws Bitrix24SecurityException - * @throws \Bitrix24\Exceptions\Bitrix24ApiException - * @throws \Bitrix24\Exceptions\Bitrix24TokenIsExpiredException - */ - public function processBatchCalls($halt = 0, $delay = self::BATCH_DELAY) - { - } -} - diff --git a/tests/.env b/tests/.env new file mode 100644 index 00000000..dc897384 --- /dev/null +++ b/tests/.env @@ -0,0 +1,25 @@ +# In all environments, the following files are loaded if they exist, +# the latter taking precedence over the former: +# +# * .env contains default values for the environment variables needed by the app +# * .env.local uncommitted file with local overrides +# * .env.$APP_ENV committed environment-specific defaults +# * .env.$APP_ENV.local uncommitted environment-specific overrides +# +# Real environment variables win over .env files. +# +# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES. +# +# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2). +# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration + +# For run integration tests you must create incoming webhook for YOUR bitrix24 portal and create .env.local file with same settings + +APP_ENV=dev +BITRIX24_WEBHOOK= +# monolog log level +INTEGRATION_TEST_LOG_LEVEL=200 +# integration tests assets +INTEGRATION_TEST_OPEN_LINE_CODE=40863c519996e505b5cde98749c97413 + +DOCUMENTATION_DEFAULT_TARGET_BRANCH= \ No newline at end of file diff --git a/tests/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceTest.php b/tests/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceTest.php new file mode 100644 index 00000000..ab38daf9 --- /dev/null +++ b/tests/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceTest.php @@ -0,0 +1,661 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Application\Contracts\ApplicationInstallations\Entity; + +use Bitrix24\SDK\Application\ApplicationStatus; +use Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Entity\ApplicationInstallationInterface; +use Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Entity\ApplicationInstallationStatus; +use Bitrix24\SDK\Application\PortalLicenseFamily; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Carbon\CarbonImmutable; +use DateInterval; +use DateTime; +use Generator; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; +use Symfony\Component\Uid\Uuid; + +#[CoversClass(ApplicationInstallationInterface::class)] +abstract class ApplicationInstallationInterfaceTest extends TestCase +{ + abstract protected function createApplicationInstallationImplementation( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId, + ): ApplicationInstallationInterface; + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test getId method')] + final public function testGetId( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId + ): void + { + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + $this->assertEquals($uuid, $installation->getId()); + } + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test getCreatedAt method')] + final public function testGetCreatedAt( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId + ): void + { + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + $this->assertEquals($createdAt, $installation->getCreatedAt()); + } + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test getCreatedAt method')] + final public function testGetUpdatedAt( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId + ): void + { + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + $this->assertEquals($updatedAt, $installation->getUpdatedAt()); + } + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test testGetBitrix24AccountId method')] + final public function testGetBitrix24AccountId( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId + ): void + { + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + $this->assertEquals($bitrix24AccountUuid, $installation->getBitrix24AccountId()); + } + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test getContactPersonId method')] + final public function testGetContactPersonId( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId + ): void + { + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + $this->assertEquals($clientContactPersonUuid, $installation->getContactPersonId()); + } + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test changeContactPerson method')] + final public function testChangeContactPerson( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId + ): void + { + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + + $newContactPersonId = Uuid::v7(); + $installation->changeContactPerson($newContactPersonId); + $this->assertEquals($newContactPersonId, $installation->getContactPersonId()); + $this->assertFalse($installation->getCreatedAt()->equalTo($installation->getUpdatedAt())); + } + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test getBitrix24PartnerContactPersonId method')] + final public function testGetBitrix24PartnerContactPersonId( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId + ): void + { + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + $this->assertEquals($partnerContactPersonUuid, $installation->getBitrix24PartnerContactPersonId()); + } + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test changeBitrix24PartnerContactPerson method')] + final public function testChangeBitrix24PartnerContactPerson( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId + ): void + { + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + + $newBitrix24PartnerContactPersonId = Uuid::v7(); + $installation->changeBitrix24PartnerContactPerson($newBitrix24PartnerContactPersonId); + $this->assertEquals($newBitrix24PartnerContactPersonId, $installation->getBitrix24PartnerContactPersonId()); + $this->assertFalse($installation->getCreatedAt()->equalTo($installation->getUpdatedAt())); + } + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test changeBitrix24Partner method')] + final public function testChangeBitrix24Partner( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId + ): void + { + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + + $newBitrix24PartnerUuid = Uuid::v7(); + $installation->changeBitrix24Partner($newBitrix24PartnerUuid); + $this->assertEquals($newBitrix24PartnerUuid, $installation->getBitrix24PartnerId()); + $this->assertFalse($installation->getCreatedAt()->equalTo($installation->getUpdatedAt())); + } + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test getExternalId method')] + final public function testGetExternalId( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId + ): void + { + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + $this->assertEquals($externalId, $installation->getExternalId()); + } + + /** + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test setExternalId method')] + final public function testSetExternalId( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId + ): void + { + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + + $newExternalId = Uuid::v7()->toRfc4122(); + $installation->setExternalId($newExternalId); + $this->assertEquals($newExternalId, $installation->getExternalId()); + + $installation->setExternalId(null); + $this->assertNull($installation->getExternalId()); + + $this->expectException(InvalidArgumentException::class); + $installation->setExternalId(''); + } + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test getStatus method')] + final public function testGetStatus( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId + ): void + { + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + $this->assertEquals($applicationInstallationStatus, $installation->getStatus()); + } + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test applicationInstalled method')] + final public function testApplicationInstalled( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId + ): void + { + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + $installation->applicationInstalled(); + $this->assertEquals(ApplicationInstallationStatus::active, $installation->getStatus()); + $this->assertFalse($installation->getCreatedAt()->equalTo($installation->getUpdatedAt())); + + // try to finish installation in wrong state + $this->expectException(InvalidArgumentException::class); + $installation->applicationInstalled(); + } + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test applicationUninstalled method')] + final public function testApplicationUninstalled( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId + ): void + { + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + $installation->applicationInstalled(); + // a few moments later + $installation->applicationUninstalled(); + $this->assertEquals(ApplicationInstallationStatus::deleted, $installation->getStatus()); + $this->assertFalse($installation->getCreatedAt()->equalTo($installation->getUpdatedAt())); + + // try to finish installation in wrong state + $this->expectException(InvalidArgumentException::class); + $installation->applicationUninstalled(); + } + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test markAsActive method')] + final public function testMarkAsActive( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId + ): void + { + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + $installation->applicationInstalled(); + + // a few moments later + $installation->markAsBlocked('block installation'); + $this->assertEquals(ApplicationInstallationStatus::blocked, $installation->getStatus()); + + // a few moments later + $installation->markAsActive('activate installation'); + $this->assertEquals(ApplicationInstallationStatus::active, $installation->getStatus()); + + + // try to activate installation in wrong state + $this->expectException(InvalidArgumentException::class); + $installation->markAsActive('activate installation in wrong state'); + } + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test markAsBlocked method')] + final public function testMarkAsBlocked( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId + ): void + { + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + $installation->applicationInstalled(); + + // a few moments later + $installation->markAsBlocked('block installation'); + $this->assertEquals(ApplicationInstallationStatus::blocked, $installation->getStatus()); + + // try to activate installation in wrong state + $this->expectException(InvalidArgumentException::class); + $installation->markAsBlocked('activate installation in wrong state'); + } + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test getApplicationStatus method')] + final public function testGetApplicationStatus( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId + ): void + { + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + $this->assertEquals($applicationStatus, $installation->getApplicationStatus()); + } + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test changeApplicationStatus method')] + final public function testChangeApplicationStatus( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId + ): void + { + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + $this->assertEquals($applicationStatus, $installation->getApplicationStatus()); + + $newApplicationStatus = ApplicationStatus::trial(); + $installation->changeApplicationStatus($newApplicationStatus); + $this->assertEquals($newApplicationStatus, $installation->getApplicationStatus()); + } + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test getPortalLicenseFamily method')] + final public function testGetPortalLicenseFamily( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId + ): void + { + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + $this->assertEquals($portalLicenseFamily, $installation->getPortalLicenseFamily()); + } + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test changePortalLicenseFamily method')] + final public function testChangePortalLicenseFamily( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId + ): void + { + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + $this->assertEquals($portalLicenseFamily, $installation->getPortalLicenseFamily()); + + $newLicenseFamily = PortalLicenseFamily::en; + $installation->changePortalLicenseFamily($newLicenseFamily); + $this->assertEquals($newLicenseFamily, $installation->getPortalLicenseFamily()); + } + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test getPortalUsersCount method')] + final public function testGetPortalUsersCount( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId + ): void + { + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + $this->assertEquals($portalUsersCount, $installation->getPortalUsersCount()); + } + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test changePortalUsersCount method')] + final public function testChangePortalUsersCount( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId + ): void + { + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + $this->assertEquals($portalUsersCount, $installation->getPortalUsersCount()); + + $newUsersCount= 249; + $installation->changePortalUsersCount($newUsersCount); + $this->assertEquals($newUsersCount, $installation->getPortalUsersCount()); + } + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test getComment method')] + final public function testGetComment( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId + ): void + { + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + $comment = 'test block'; + $installation->applicationInstalled(); + $installation->markAsBlocked($comment); + $this->assertEquals($comment, $installation->getComment()); + } + + public static function applicationInstallationDataProvider(): Generator + { + yield 'status-new-all-fields' => [ + Uuid::v7(), // uuid + ApplicationInstallationStatus::new, // application installation status + CarbonImmutable::now(), // created at + CarbonImmutable::createFromMutable((new DateTime())->add(new DateInterval('PT1H'))), // updated at + Uuid::v7(), // bitrix24 account id + ApplicationStatus::subscription(), // application status from bitrix24 api call response + PortalLicenseFamily::nfr, // portal license family value + 42, // bitrix24 portal users count + Uuid::v7(), // ?client contact person id + Uuid::v7(), // ?partner contact person id + Uuid::v7(), // ?partner id + Uuid::v7()->toRfc4122(), // external id + ]; + yield 'status-new-without-all-optional-fields' => [ + Uuid::v7(), // uuid + ApplicationInstallationStatus::new, // application installation status + CarbonImmutable::now(), // created at + CarbonImmutable::createFromMutable((new DateTime())->add(new DateInterval('PT1H'))), // updated at + Uuid::v7(), // bitrix24 account id + ApplicationStatus::subscription(), // application status from bitrix24 api call response + PortalLicenseFamily::nfr, // portal license family value + null, // bitrix24 portal users count + null, // ?client contact person id + null, // ?partner contact person id + null, // ?partner id + null, // external id + ]; + } +} \ No newline at end of file diff --git a/tests/Application/Contracts/ApplicationInstallations/Repository/ApplicationInstallationRepositoryInterfaceTest.php b/tests/Application/Contracts/ApplicationInstallations/Repository/ApplicationInstallationRepositoryInterfaceTest.php new file mode 100644 index 00000000..f7024979 --- /dev/null +++ b/tests/Application/Contracts/ApplicationInstallations/Repository/ApplicationInstallationRepositoryInterfaceTest.php @@ -0,0 +1,363 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Application\Contracts\ApplicationInstallations\Repository; + +use Bitrix24\SDK\Application\ApplicationStatus; +use Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Entity\ApplicationInstallationInterface; +use Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Entity\ApplicationInstallationStatus; +use Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Exceptions\ApplicationInstallationNotFoundException; +use Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Repository\ApplicationInstallationRepositoryInterface; +use Bitrix24\SDK\Application\PortalLicenseFamily; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Carbon\CarbonImmutable; +use DateInterval; +use DateTime; +use Generator; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; +use Symfony\Component\Uid\Uuid; + +#[CoversClass(ApplicationInstallationRepositoryInterface::class)] +abstract class ApplicationInstallationRepositoryInterfaceTest extends TestCase +{ + abstract protected function createApplicationInstallationImplementation( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId, + ): ApplicationInstallationInterface; + + abstract protected function createApplicationInstallationRepositoryImplementation(): ApplicationInstallationRepositoryInterface; + + /** + * @throws ApplicationInstallationNotFoundException + */ + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test save method for install start use case')] + final public function testSave( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId, + ): void + { + $appInstallationRepo = $this->createApplicationInstallationRepositoryImplementation(); + + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + $appInstallationRepo->save($installation); + + $this->assertEquals($installation, $appInstallationRepo->getById($installation->getId())); + } + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test getById method for install start use case')] + final public function testGetByIdHappyPath( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId, + ): void + { + $appInstallationRepo = $this->createApplicationInstallationRepositoryImplementation(); + + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + $appInstallationRepo->save($installation); + + $this->assertEquals($installation, $appInstallationRepo->getById($installation->getId())); + } + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test getById method for install start use case')] + final public function testGetByIdWithNonExistsEntity( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId, + ): void + { + $appInstallationRepo = $this->createApplicationInstallationRepositoryImplementation(); + + $this->expectException(ApplicationInstallationNotFoundException::class); + $appInstallationRepo->getById(Uuid::v7()); + } + + /** + * @throws ApplicationInstallationNotFoundException + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test delete method')] + final public function testDeleteWithHappyPath( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId, + ): void + { + $appInstallationRepo = $this->createApplicationInstallationRepositoryImplementation(); + + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + // successfully finish installation flow + $installation->applicationInstalled(); + + // few moments later application uninstalled + // we receive ON_APPLICATION_UNINSTALL event and mark application installation as uninstalled: status = deleted + $installation->applicationUninstalled(); + $appInstallationRepo->save($installation); + + // if we want we can delete application installation from repository + $appInstallationRepo->delete($installation->getId()); + + $this->expectException(ApplicationInstallationNotFoundException::class); + $appInstallationRepo->getById($installation->getId()); + } + + /** + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test delete method with unknown id')] + final public function testDeleteWithUnknownId( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId, + ): void + { + $appInstallationRepo = $this->createApplicationInstallationRepositoryImplementation(); + + // try to delete unknown installation + $this->expectException(ApplicationInstallationNotFoundException::class); + $appInstallationRepo->delete(Uuid::v7()); + } + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test delete method with wrong state')] + final public function testDeleteWithWrongState( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId, + ): void + { + $appInstallationRepo = $this->createApplicationInstallationRepositoryImplementation(); + + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + $appInstallationRepo->save($installation); + + $this->expectException(InvalidArgumentException::class); + $appInstallationRepo->delete($installation->getId()); + } + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test findByBitrix24AccountId method')] + final public function testFindByBitrix24AccountId( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId, + ): void + { + $appInstallationRepo = $this->createApplicationInstallationRepositoryImplementation(); + + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + $appInstallationRepo->save($installation); + + $this->assertEquals([$installation], $appInstallationRepo->findByBitrix24AccountId($bitrix24AccountUuid)); + } + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test findByBitrix24AccountId method with unknown id')] + final public function testFindByBitrix24AccountIdWithUnknownId( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId, + ): void + { + $appInstallationRepo = $this->createApplicationInstallationRepositoryImplementation(); + + $this->assertEquals([], $appInstallationRepo->findByBitrix24AccountId(Uuid::v7())); + } + + /** + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test findByExternalId method')] + final public function testFindByExternalId( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId, + ): void + { + $appInstallationRepo = $this->createApplicationInstallationRepositoryImplementation(); + + $installation = $this->createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + $externalId = Uuid::v7()->toRfc4122(); + $installation->setExternalId($externalId); + $appInstallationRepo->save($installation); + + $this->assertEquals([$installation], $appInstallationRepo->findByExternalId($externalId)); + } + + #[Test] + #[DataProvider('applicationInstallationDataProvider')] + #[TestDox('test findByExternalId method with unknown id')] + final public function testFindByExternalIdWithUnknownId( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId, + ): void + { + $appInstallationRepo = $this->createApplicationInstallationRepositoryImplementation(); + + $externalId = Uuid::v7()->toRfc4122(); + $this->assertEquals([], $appInstallationRepo->findByExternalId($externalId)); + } + + public static function applicationInstallationDataProvider(): Generator + { + yield 'status-new-all-fields' => [ + Uuid::v7(), // uuid + ApplicationInstallationStatus::new, // application installation status + CarbonImmutable::now(), // created at + CarbonImmutable::createFromMutable((new DateTime())->add(new DateInterval('PT1H'))), // updated at + Uuid::v7(), // bitrix24 account id + ApplicationStatus::subscription(), // application status from bitrix24 api call response + PortalLicenseFamily::nfr, // portal license family value + 42, // bitrix24 portal users count + Uuid::v7(), // ?client contact person id + Uuid::v7(), // ?partner contact person id + Uuid::v7(), // ?partner id + Uuid::v7()->toRfc4122(), // external id + ]; + yield 'status-new-without-all-optional-fields' => [ + Uuid::v7(), // uuid + ApplicationInstallationStatus::new, // application installation status + CarbonImmutable::now(), // created at + CarbonImmutable::createFromMutable((new DateTime())->add(new DateInterval('PT1H'))), // updated at + Uuid::v7(), // bitrix24 account id + ApplicationStatus::subscription(), // application status from bitrix24 api call response + PortalLicenseFamily::nfr, // portal license family value + null, // bitrix24 portal users count + null, // ?client contact person id + null, // ?partner contact person id + null, // ?partner id + null, // external id + ]; + } +} \ No newline at end of file diff --git a/tests/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php b/tests/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php new file mode 100644 index 00000000..c5c24274 --- /dev/null +++ b/tests/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php @@ -0,0 +1,820 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Application\Contracts\Bitrix24Accounts\Entity; + +use Bitrix24\SDK\Application\ApplicationStatus; +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountInterface; +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountStatus; +use Bitrix24\SDK\Core\Credentials\AuthToken; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException; +use Bitrix24\SDK\Core\Response\DTO\RenewedAuthToken; +use Carbon\CarbonImmutable; +use Generator; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; +use Symfony\Component\Uid\Uuid; +use Throwable; + +#[CoversClass(Bitrix24AccountInterface::class)] +abstract class Bitrix24AccountInterfaceTest extends TestCase +{ + abstract protected function createBitrix24AccountImplementation( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): Bitrix24AccountInterface; + + #[Test] + #[DataProvider('bitrix24AccountDataProvider')] + #[TestDox('test getId method')] + final public function testGetId( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertEquals($uuid, $bitrix24Account->getId()); + } + + #[Test] + #[DataProvider('bitrix24AccountDataProvider')] + #[TestDox('test getBitrix24UserId method')] + final public function testGetBitrix24UserId( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertEquals($bitrix24UserId, $bitrix24Account->getBitrix24UserId()); + } + + #[Test] + #[DataProvider('bitrix24AccountDataProvider')] + #[TestDox('test isBitrix24UserAdmin method')] + final public function testisBitrix24UserAdmin( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertEquals($isBitrix24UserAdmin, $bitrix24Account->isBitrix24UserAdmin()); + } + + #[Test] + #[DataProvider('bitrix24AccountDataProvider')] + #[TestDox('test getMemberId method')] + final public function testGetMemberId( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertEquals($memberId, $bitrix24Account->getMemberId()); + } + + #[Test] + #[DataProvider('bitrix24AccountDataProvider')] + #[TestDox('test getDomainUrl method')] + final public function testGetDomainUrl( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertEquals($domainUrl, $bitrix24Account->getDomainUrl()); + } + + #[Test] + #[DataProvider('bitrix24AccountDataProvider')] + #[TestDox('test getStatus method')] + final public function testGetStatus( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertEquals($bitrix24AccountStatus, $bitrix24Account->getStatus()); + } + + #[Test] + #[DataProvider('bitrix24AccountDataProvider')] + #[TestDox('test getAuthToken method')] + final public function testGetAuthToken( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertEquals($authToken, $bitrix24Account->getAuthToken()); + } + + #[Test] + #[DataProvider('bitrix24AccountDataProvider')] + #[TestDox('test renewAuthToken method')] + final public function testRenewAuthToken( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $newAuthToken = new AuthToken('access_token-2', 'refresh_token=2', 1609459202); + $applicationStatus = ApplicationStatus::subscription(); + + $renewedAuthToken = new RenewedAuthToken( + $newAuthToken, + $memberId, + 'https://bitrix24.com/client', + 'https://bitrix24.com/server', + $applicationStatus, + $domainUrl + ); + $bitrix24Account->renewAuthToken($renewedAuthToken); + + + $this->assertEquals($newAuthToken, $bitrix24Account->getAuthToken()); + } + + #[Test] + #[DataProvider('bitrix24AccountDataProvider')] + #[TestDox('test getApplicationVersion method')] + final public function testGetApplicationVersion( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertEquals($applicationVersion, $bitrix24Account->getApplicationVersion()); + } + + + #[Test] + #[DataProvider('bitrix24AccountDataProvider')] + #[TestDox('test getApplicationScope method')] + final public function testGetApplicationScope( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertEquals($applicationScope, $bitrix24Account->getApplicationScope()); + } + + #[Test] + #[DataProvider('bitrix24AccountDataProvider')] + #[TestDox('test changeDomainUrl method')] + final public function testChangeDomainUrl( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $newDomainUrl = 'new-bitrix24.com'; + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24Account->changeDomainUrl($newDomainUrl); + $this->assertEquals($newDomainUrl, $bitrix24Account->getDomainUrl()); + } + + /** + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test applicationInstalled method')] + final public function testApplicationInstalled( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope, + string $applicationToken, + ?Throwable $throwable + ): void + { + if ($throwable instanceof \Throwable) { + $this->expectException($throwable::class); + } + + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24Account->applicationInstalled($applicationToken); + $this->assertTrue($bitrix24Account->isApplicationTokenValid($applicationToken)); + } + + #[Test] + #[DataProvider('bitrix24AccountForUninstallDataProvider')] + #[TestDox('test applicationUninstalled method')] + final public function testApplicationUninstalled( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope, + string $applicationToken, + ?Throwable $throwable + ): void + { + if ($throwable instanceof \Throwable) { + $this->expectException($throwable::class); + } + + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24Account->applicationInstalled($applicationToken); + $bitrix24Account->applicationUninstalled($applicationToken); + $this->assertEquals(Bitrix24AccountStatus::deleted, $bitrix24Account->getStatus()); + } + + /** + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('bitrix24AccountWithStatusNewDataProvider')] + #[TestDox('test isApplicationTokenValid method')] + final public function testIsApplicationTokenValid( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope, + string $applicationToken, + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertFalse($bitrix24Account->isApplicationTokenValid($applicationToken)); + $bitrix24Account->applicationInstalled($applicationToken); + $this->assertTrue($bitrix24Account->isApplicationTokenValid($applicationToken)); + } + + /** + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('bitrix24AccountWithStatusNewDataProvider')] + #[TestDox('test getCreatedAt method')] + final public function testGetCreatedAt( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope, + string $applicationToken, + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertTrue($bitrix24Account->getCreatedAt()->equalTo($createdAt)); + $bitrix24Account->applicationInstalled($applicationToken); + $this->assertTrue($bitrix24Account->getCreatedAt()->equalTo($createdAt)); + } + + /** + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('bitrix24AccountWithStatusNewDataProvider')] + #[TestDox('test getUpdatedAt method')] + final public function testGetUpdatedAt( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope, + string $applicationToken, + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertTrue($bitrix24Account->getUpdatedAt()->equalTo($updatedAt)); + $bitrix24Account->applicationInstalled($applicationToken); + $this->assertFalse($bitrix24Account->getUpdatedAt()->equalTo($createdAt)); + } + + /** + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('bitrix24AccountWithStatusNewDataProvider')] + #[TestDox('test updateApplicationVersion method')] + final public function testUpdateApplicationVersion( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope, + string $applicationToken, + int $newApplicationVersion, + Scope $newApplicationScope, + ?Throwable $throwable + ): void + { + if ($throwable instanceof \Throwable) { + $this->expectException($throwable::class); + } + + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24Account->applicationInstalled($applicationToken); + $bitrix24Account->updateApplicationVersion($newApplicationVersion, $newApplicationScope); + $this->assertEquals($newApplicationVersion, $bitrix24Account->getApplicationVersion()); + $this->assertTrue($newApplicationScope->equal($bitrix24Account->getApplicationScope())); + } + + /** + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test markAsBlocked and getComment methods')] + final public function testMarkAsBlocked( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope, + string $applicationToken, + ?Throwable $throwable + ): void + { + if ($throwable instanceof \Throwable) { + $this->expectException($throwable::class); + } + + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24Account->applicationInstalled($applicationToken); + + $comment = 'block account just for fun'; + $bitrix24Account->markAsBlocked($comment); + $this->assertEquals(Bitrix24AccountStatus::blocked, $bitrix24Account->getStatus()); + $this->assertEquals($comment, $bitrix24Account->getComment()); + } + + /** + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test markAsActive and getComment methods')] + final public function testMarkAsActive( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope, + string $applicationToken, + ?Throwable $throwable + ): void + { + if ($throwable instanceof \Throwable) { + $this->expectException($throwable::class); + } + + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24Account->applicationInstalled($applicationToken); + + $comment = 'block account just for fun'; + $bitrix24Account->markAsBlocked($comment); + $this->assertEquals(Bitrix24AccountStatus::blocked, $bitrix24Account->getStatus()); + $this->assertEquals($comment, $bitrix24Account->getComment()); + $comment = 'activate account'; + $bitrix24Account->markAsActive($comment); + $this->assertEquals(Bitrix24AccountStatus::active, $bitrix24Account->getStatus()); + $this->assertEquals($comment, $bitrix24Account->getComment()); + } + + /** + * @throws UnknownScopeCodeException + */ + public static function bitrix24AccountWithStatusNewDataProvider(): Generator + { + yield 'valid-update' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::new, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope(['crm', 'task']), + 'application_token', + 2, + new Scope(['crm', 'task', 'telephony']), + null + ]; + yield 'valid-update-same-scope' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::new, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope(['crm', 'task']), + 'application_token', + 2, + new Scope(['task','crm']), + null + ]; + yield 'valid-downgrade-scope' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::new, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope([]), + 'application_token', + 2, + new Scope(['task','crm']), + null + ]; + yield 'invalid-version' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::new, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope(['crm', 'task']), + 'application_token', + 1, + new Scope(['crm', 'task', 'telephony']), + new InvalidArgumentException() + ]; + } + + public static function bitrix24AccountForUninstallDataProvider(): Generator + { + yield 'empty-application-token' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::active, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope(['crm', 'task']), + '', + new InvalidArgumentException() + ]; + + yield 'account-status-new' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::new, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope(['crm', 'task']), + 'application_token_value', + null + ]; + yield 'account-status-active' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::active, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope(['crm', 'task']), + 'application_token_value', + new InvalidArgumentException() + + ]; + yield 'account-status-blocked' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::blocked, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope(['crm', 'task']), + 'application_token_value', + new InvalidArgumentException() + ]; + yield 'account-status-deleted' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::deleted, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope(['crm', 'task']), + 'application_token_value', + new InvalidArgumentException() + ]; + } + + /** + * @throws UnknownScopeCodeException + */ + public static function bitrix24AccountForInstallDataProvider(): Generator + { + yield 'empty-application-token' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::new, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope(['crm', 'task']), + '', + new InvalidArgumentException() + ]; + + yield 'account-status-new' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::new, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope(['crm', 'task']), + 'application_token_value', + null + ]; + yield 'account-status-active' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::active, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope(['crm', 'task']), + 'application_token_value', + new InvalidArgumentException() + ]; + yield 'account-status-blocked' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::blocked, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope(['crm', 'task']), + 'application_token_value', + new InvalidArgumentException() + ]; + yield 'account-status-deleted' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::deleted, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope(['crm', 'task']), + 'application_token_value', + new InvalidArgumentException() + ]; + } + + /** + * @throws UnknownScopeCodeException + */ + public static function bitrix24AccountDataProvider(): Generator + { + yield 'account-status-new' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::new, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope(['crm', 'task']) + ]; + yield 'account-status-active' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::active, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope(['crm', 'task']) + ]; + } +} \ No newline at end of file diff --git a/tests/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterfaceTest.php b/tests/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterfaceTest.php new file mode 100644 index 00000000..e3fb3818 --- /dev/null +++ b/tests/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterfaceTest.php @@ -0,0 +1,886 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Application\Contracts\Bitrix24Accounts\Repository; + +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountInterface; +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountStatus; +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Exceptions\Bitrix24AccountNotFoundException; +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Repository\Bitrix24AccountRepositoryInterface; +use Bitrix24\SDK\Core\Credentials\AuthToken; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException; +use Carbon\CarbonImmutable; +use Generator; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; +use Symfony\Component\Uid\Uuid; + +#[CoversClass(Bitrix24AccountInterface::class)] +abstract class Bitrix24AccountRepositoryInterfaceTest extends TestCase +{ + abstract protected function createBitrix24AccountImplementation( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): Bitrix24AccountInterface; + + abstract protected function createBitrix24AccountRepositoryImplementation(): Bitrix24AccountRepositoryInterface; + + /** + * @throws Bitrix24AccountNotFoundException + */ + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test save method for install start use case')] + final public function testSave( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + + $bitrix24AccountRepository->save($bitrix24Account); + + $acc = $bitrix24AccountRepository->getById($bitrix24Account->getId()); + $this->assertEquals($bitrix24Account, $acc); + } + + #[Test] + #[TestDox('test getById method with non existing account')] + public function testGetByIdNotExists(): void + { + $this->expectException(Bitrix24AccountNotFoundException::class); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + $bitrix24AccountRepository->getById(Uuid::v7()); + } + + /** + * @throws InvalidArgumentException + * @throws Bitrix24AccountNotFoundException + */ + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test delete method for happy path')] + final public function testDeleteHappyPath( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + + // application installed + $applicationToken = 'application_token'; + $bitrix24Account->applicationInstalled($applicationToken); + $bitrix24AccountRepository->save($bitrix24Account); + + // a few moments later + $account = $bitrix24AccountRepository->getById($uuid); + $account->applicationUninstalled($applicationToken); + + $bitrix24AccountRepository->save($bitrix24Account); + + $bitrix24AccountRepository->delete($uuid); + + $this->expectException(Bitrix24AccountNotFoundException::class); + $bitrix24AccountRepository->getById($uuid); + } + + /** + * @throws Bitrix24AccountNotFoundException + */ + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test delete method for account not in deleted state')] + final public function testDeleteNotInDeletedState( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + + $bitrix24AccountRepository->save($bitrix24Account); + + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); + + $this->expectException(InvalidArgumentException::class); + $bitrix24AccountRepository->delete($uuid); + } + + /** + * @throws InvalidArgumentException + */ + #[Test] + #[TestDox('test delete method with non existing account')] + public function testDeleteWithIdNotExists(): void + { + $this->expectException(Bitrix24AccountNotFoundException::class); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + $bitrix24AccountRepository->delete(Uuid::v7()); + } + + #[Test] + #[TestDox('test findOneAdminByMemberId method with empty member_id')] + public function testFindOneAdminByMemberIdWithEmptyArgs(): void + { + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + $this->expectException(InvalidArgumentException::class); + /** @phpstan-ignore-next-line */ + $bitrix24AccountRepository->findOneAdminByMemberId(''); + } + + /** + * @throws Bitrix24AccountNotFoundException + */ + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test findOneAdminByMemberId method with happy path')] + final public function testFindOneAdminByMemberIdWithHappyPath( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + + $bitrix24AccountRepository->save($bitrix24Account); + + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); + + + $found = $bitrix24AccountRepository->findOneAdminByMemberId($memberId); + $this->assertEquals($acc, $found); + } + + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test findOneAdminByMemberId method with simple user')] + final public function testFindOneAdminByMemberIdWithSimpleUser( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, false, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + + $bitrix24AccountRepository->save($bitrix24Account); + + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); + + $found = $bitrix24AccountRepository->findOneAdminByMemberId($memberId); + $this->assertNull($found); + } + + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test findByMemberId method with happy path')] + final public function testFindByMemberIdWithHappyPath( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + + $bitrix24AccountRepository->save($bitrix24Account); + + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); + + $found = $bitrix24AccountRepository->findByMemberId($memberId); + $this->assertEquals($bitrix24Account, $found[0]); + } + + #[Test] + #[TestDox('test findByMemberId method with happy path - not found')] + final public function testFindByMemberIdWithHappyPathNotFound(): void + { + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + $found = $bitrix24AccountRepository->findByMemberId('member_id'); + $this->assertEquals([], $found); + } + + #[Test] + #[TestDox('test findByMemberId method with empty member id')] + final public function testFindByMemberIdWithEmptyMemberId(): void + { + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + $this->expectException(InvalidArgumentException::class); + /** @phpstan-ignore-next-line */ + $bitrix24AccountRepository->findByMemberId(''); + } + + /** + * @throws Bitrix24AccountNotFoundException + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test findByMemberId method with blocked account happy path')] + final public function testFindByMemberIdWithBlockedAccountHappyPath( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + + $bitrix24AccountRepository->save($bitrix24Account); + + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); + $acc->markAsBlocked('block by admin'); + $bitrix24AccountRepository->save($acc); + + $found = $bitrix24AccountRepository->findByMemberId($memberId, Bitrix24AccountStatus::blocked); + $this->assertEquals($acc, $found[0]); + } + + /** + * @throws Bitrix24AccountNotFoundException + */ + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test findByMemberId method with account status but account not found')] + final public function testFindByMemberIdWithAccountStatusAccountNotFound( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + + $bitrix24AccountRepository->save($bitrix24Account); + + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); + + $found = $bitrix24AccountRepository->findByMemberId($memberId, Bitrix24AccountStatus::blocked); + $this->assertEquals([], $found); + } + + /** + * @throws Bitrix24AccountNotFoundException + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test findByMemberId method with is admin happy path')] + final public function testFindByMemberIdWithIsAdminHappyPath( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + + $bitrix24AccountRepository->save($bitrix24Account); + + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); + + $found = $bitrix24AccountRepository->findByMemberId($memberId, null, true); + $this->assertEquals($acc, $found[0]); + } + + /** + * @throws Bitrix24AccountNotFoundException + */ + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test findByMemberId method with is admin - not found')] + final public function testFindByMemberIdWithIsAdminNotFound( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, false, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + + $bitrix24AccountRepository->save($bitrix24Account); + + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); + + $found = $bitrix24AccountRepository->findByMemberId($memberId, null, true); + $this->assertEquals([], $found); + } + + /** + * @throws Bitrix24AccountNotFoundException + */ + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test findByMemberId method with all args')] + final public function testFindByMemberIdWithAllArgs( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, false, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + + $bitrix24AccountRepository->save($bitrix24Account); + + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); + + $found = $bitrix24AccountRepository->findByMemberId($memberId, Bitrix24AccountStatus::new, false); + $this->assertEquals($acc, $found[0]); + } + + /** + * @throws Bitrix24AccountNotFoundException + */ + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test findByDomain method with happy path')] + final public function testFindByDomainWithHappyPath( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + + $bitrix24AccountRepository->save($bitrix24Account); + + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); + + $found = $bitrix24AccountRepository->findByDomain($domainUrl); + $this->assertEquals($bitrix24Account, $found[0]); + } + + #[Test] + #[TestDox('test findByDomain method with happy path - not found')] + final public function testFindByDomainWithHappyPathNotFound(): void + { + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + $found = $bitrix24AccountRepository->findByDomain('test.com'); + $this->assertEquals([], $found); + } + + #[Test] + #[TestDox('test findByDomain method with empty domain url')] + final public function testFindByDomainWithEmptyDomainUrl(): void + { + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + $this->expectException(InvalidArgumentException::class); + /** @phpstan-ignore-next-line */ + $bitrix24AccountRepository->findByDomain(''); + } + + /** + * @throws Bitrix24AccountNotFoundException + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test findByDomain method with blocked account happy path')] + final public function testFindByDomainWithBlockedAccountHappyPath( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + + $bitrix24AccountRepository->save($bitrix24Account); + + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); + $acc->markAsBlocked('block by admin'); + $bitrix24AccountRepository->save($acc); + + $found = $bitrix24AccountRepository->findByDomain($domainUrl, Bitrix24AccountStatus::blocked); + $this->assertEquals($acc, $found[0]); + } + + /** + * @throws Bitrix24AccountNotFoundException + */ + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test findByDomain method with account status but account not found')] + final public function testFindByDomainWithAccountStatusAccountNotFound( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + + $bitrix24AccountRepository->save($bitrix24Account); + + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); + + $found = $bitrix24AccountRepository->findByDomain($domainUrl, Bitrix24AccountStatus::blocked); + $this->assertEquals([], $found); + } + + /** + * @throws Bitrix24AccountNotFoundException + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test findByDomain method with is admin happy path')] + final public function testFindByDomainWithIsAdminHappyPath( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + + $bitrix24AccountRepository->save($bitrix24Account); + + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); + + $found = $bitrix24AccountRepository->findByDomain($domainUrl, null, true); + $this->assertEquals($acc, $found[0]); + } + + /** + * @throws Bitrix24AccountNotFoundException + */ + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test findByDomain method with is admin - not found')] + final public function testFindByDomainWithIsAdminNotFound( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, false, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + + $bitrix24AccountRepository->save($bitrix24Account); + + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); + + $found = $bitrix24AccountRepository->findByDomain($memberId, null, true); + $this->assertEquals([], $found); + } + + /** + * @throws Bitrix24AccountNotFoundException + */ + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test findByDomain method with all args')] + final public function testFindByDomainWithAllArgs( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, false, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + + $bitrix24AccountRepository->save($bitrix24Account); + + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); + + $found = $bitrix24AccountRepository->findByDomain($domainUrl, Bitrix24AccountStatus::new, false); + $this->assertEquals($acc, $found[0]); + } + + /** + * @throws UnknownScopeCodeException + */ + public static function bitrix24AccountWithStatusNewDataProvider(): Generator + { + yield 'valid-update' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::new, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope(['crm', 'task']), + 'application_token', + 2, + new Scope(['crm', 'task', 'telephony']), + null + ]; + yield 'valid-update-same-scope' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::new, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope(['crm', 'task']), + 'application_token', + 2, + new Scope(['task', 'crm']), + null + ]; + yield 'valid-downgrade-scope' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::new, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope([]), + 'application_token', + 2, + new Scope(['task', 'crm']), + null + ]; + yield 'invalid-version' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::new, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope(['crm', 'task']), + 'application_token', + 1, + new Scope(['crm', 'task', 'telephony']), + new InvalidArgumentException() + ]; + } + + public static function bitrix24AccountForUninstallDataProvider(): Generator + { + yield 'empty-application-token' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::active, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope(['crm', 'task']), + '', + new InvalidArgumentException() + ]; + + yield 'account-status-new' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::new, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope(['crm', 'task']), + 'application_token_value', + null + ]; + yield 'account-status-active' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::active, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope(['crm', 'task']), + 'application_token_value', + new InvalidArgumentException() + + ]; + yield 'account-status-blocked' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::blocked, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope(['crm', 'task']), + 'application_token_value', + new InvalidArgumentException() + ]; + yield 'account-status-deleted' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::deleted, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope(['crm', 'task']), + 'application_token_value', + new InvalidArgumentException() + ]; + } + + /** + * @throws UnknownScopeCodeException + */ + public static function bitrix24AccountForInstallDataProvider(): Generator + { + yield 'account-status-new' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::new, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope(['crm', 'task']), + 'application_token_value', + null + ]; + } + + /** + * @throws UnknownScopeCodeException + */ + public static function bitrix24AccountDataProvider(): Generator + { + yield 'account-status-new' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::new, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope(['crm', 'task']) + ]; + yield 'account-status-active' => [ + Uuid::v7(), + 12345, + true, + 'member123', + 'https://example.com', + Bitrix24AccountStatus::active, + new AuthToken('access_token', 'refresh_token', 1609459200), + CarbonImmutable::now(), + CarbonImmutable::now(), + 1, + new Scope(['crm', 'task']) + ]; + } +} \ No newline at end of file diff --git a/tests/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterfaceTest.php b/tests/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterfaceTest.php new file mode 100644 index 00000000..140f9eb9 --- /dev/null +++ b/tests/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterfaceTest.php @@ -0,0 +1,650 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Application\Contracts\Bitrix24Partners\Entity; + +use Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Entity\Bitrix24PartnerInterface; +use Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Entity\Bitrix24PartnerStatus; +use Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Events\Bitrix24PartnerExternalIdChangedEvent; +use Bitrix24\SDK\Application\Contracts\Events\AggregateRootEventsEmitterInterface; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Tests\Builders\DemoDataGenerator; +use Carbon\CarbonImmutable; +use Generator; +use libphonenumber\NumberParseException; +use libphonenumber\PhoneNumber; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; +use Symfony\Component\Uid\Uuid; +use Throwable; + +#[CoversClass(Bitrix24PartnerInterface::class)] +abstract class Bitrix24PartnerInterfaceTest extends TestCase +{ + abstract protected function createBitrix24PartnerImplementation( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): Bitrix24PartnerInterface|AggregateRootEventsEmitterInterface; + + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test getId method')] + final public function testGetId( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $bitrix24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + $this->assertEquals($uuid, $bitrix24Partner->getId()); + } + + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test getCreatedAt method')] + final public function testGetCreatedAt( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $bitrix24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + $this->assertEquals($createdAt, $bitrix24Partner->getCreatedAt()); + } + + /** + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test getUpdatedAt method')] + final public function testGetUpdatedAt( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $bitrix24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + $bitrix24Partner->setTitle('new title'); + $this->assertNotEquals($updatedAt, $bitrix24Partner->getUpdatedAt()); + } + + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test setExternalId method with empty string')] + final public function testSetExternalId( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $bitrix24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + + $newExternalId = Uuid::v7()->toRfc4122(); + $bitrix24Partner->setExternalId($newExternalId); + $this->assertEquals($newExternalId, $bitrix24Partner->getExternalId()); + } + + /** + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test setExternalId method with null')] + final public function testSetExternalIdWithNull( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $bitrix24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + $bitrix24Partner->setExternalId(null); + $this->assertNull($bitrix24Partner->getExternalId()); + } + + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test setExternalId method')] + final public function testSetExternalIdWithEmptyString( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $bitrix24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + $this->expectException(InvalidArgumentException::class); + $bitrix24Partner->setExternalId(''); + } + + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test getStatus method')] + final public function testGetStatus( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $bitrix24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + $this->assertEquals($bitrix24PartnerStatus, $bitrix24Partner->getStatus()); + } + + /** + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test markAsActive method')] + final public function testMarkAsActive( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $bitrix24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + + $blockComment = 'block partner'; + $bitrix24Partner->markAsBlocked($blockComment); + $this->assertEquals(Bitrix24PartnerStatus::blocked, $bitrix24Partner->getStatus()); + $this->assertEquals($blockComment, $bitrix24Partner->getComment()); + + $bitrix24Partner->markAsActive(null); + $this->assertEquals(Bitrix24PartnerStatus::active, $bitrix24Partner->getStatus()); + $this->assertNull($bitrix24Partner->getComment()); + + $this->expectException(InvalidArgumentException::class); + $bitrix24Partner->markAsActive('mark as active'); + } + + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test markAsBlocked method')] + final public function testMarkAsBlocked( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $bitrix24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + + $blockComment = 'block partner'; + $bitrix24Partner->markAsBlocked($blockComment); + $this->assertEquals(Bitrix24PartnerStatus::blocked, $bitrix24Partner->getStatus()); + $this->assertEquals($blockComment, $bitrix24Partner->getComment()); + + $this->expectException(InvalidArgumentException::class); + $bitrix24Partner->markAsBlocked('mark as active'); + } + + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test markAsBlocked method')] + final public function testMarkAsDeleted( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $bitrix24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + + $comment = 'delete partner'; + $bitrix24Partner->markAsDeleted($comment); + $this->assertEquals(Bitrix24PartnerStatus::deleted, $bitrix24Partner->getStatus()); + $this->assertEquals($comment, $bitrix24Partner->getComment()); + + $this->expectException(InvalidArgumentException::class); + $bitrix24Partner->markAsBlocked('mark as deleted'); + } + + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test getTitle method')] + final public function testGetTitle( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $bitrix24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + $this->assertEquals($title, $bitrix24Partner->getTitle()); + } + + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test setTitle method')] + final public function testSetTitle( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $bitrix24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + $newTitle = 'new title'; + $bitrix24Partner->setTitle($newTitle); + $this->assertEquals($newTitle, $bitrix24Partner->getTitle()); + + $newTitle = ''; + $this->expectException(InvalidArgumentException::class); + /** @phpstan-ignore-next-line */ + $bitrix24Partner->setTitle($newTitle); + } + + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test getSite method')] + final public function testGetSite( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $bitrix24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + $this->assertEquals($site, $bitrix24Partner->getSite()); + } + + /** + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test setSite method')] + final public function testSetSite( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $bitrix24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + $newSite = 'https://new-partner-site.com'; + $bitrix24Partner->setSite($newSite); + $this->assertEquals($newSite, $bitrix24Partner->getSite()); + + $bitrix24Partner->setSite(null); + $this->assertNull($bitrix24Partner->getSite()); + + $this->expectException(InvalidArgumentException::class); + /** @phpstan-ignore-next-line */ + $bitrix24Partner->setSite(''); + } + + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test getPhone method')] + final public function testGetPhone( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $bitrix24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + $this->assertEquals($phoneNumber, $bitrix24Partner->getPhone()); + } + + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test setPhone method')] + final public function testSetPhone( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $bitrix24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + $newPhone = DemoDataGenerator::getMobilePhone(); + $bitrix24Partner->setPhone($newPhone); + $this->assertEquals($newPhone, $bitrix24Partner->getPhone()); + + $bitrix24Partner->setPhone(null); + $this->assertNull($bitrix24Partner->getPhone()); + } + + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test getEmail method')] + final public function testGetEmail( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $bitrix24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + $this->assertEquals($email, $bitrix24Partner->getEmail()); + } + + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test setEmail method')] + final public function testSetEmail( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $bitrix24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + + $newEmail = DemoDataGenerator::getEmail(); + $bitrix24Partner->setEmail($newEmail); + $this->assertEquals($newEmail, $bitrix24Partner->getEmail()); + + $bitrix24Partner->setEmail(null); + $this->assertNull($bitrix24Partner->getEmail()); + + $this->expectException(InvalidArgumentException::class); + /** @phpstan-ignore-next-line */ + $bitrix24Partner->setEmail(''); + } + + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test setEmail method with invalid email')] + final public function testSetEmailWithInvalidEmail( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $bitrix24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + + $newEmail = '@partner.com'; + $this->expectException(InvalidArgumentException::class); + $bitrix24Partner->setEmail($newEmail); + } + + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test getBitrix24PartnerId')] + final public function testGetBitrix24PartnerId( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $bitrix24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + $this->assertEquals($bitrix24PartnerId, $bitrix24Partner->getBitrix24PartnerId()); + } + + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test setBitrix24PartnerId')] + final public function testSetBitrix24PartnerId( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $bitrix24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + $newBitrix24PartnerId = 123; + $bitrix24Partner->setBitrix24PartnerId($newBitrix24PartnerId); + $this->assertEquals($newBitrix24PartnerId, $bitrix24Partner->getBitrix24PartnerId()); + + $bitrix24Partner->setBitrix24PartnerId(null); + $this->assertNull($bitrix24Partner->getBitrix24PartnerId()); + + $this->expectException(InvalidArgumentException::class); + /** @phpstan-ignore-next-line */ + $bitrix24Partner->setBitrix24PartnerId(0); + } + + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test getOpenLineId')] + final public function testGetOpenLineId( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $bitrix24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + $this->assertEquals($openLineId, $bitrix24Partner->getOpenLineId()); + } + + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test setOpenLineId')] + final public function testSetOpenLineId( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $bitrix24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + $newOpenLineId = Uuid::v7()->toRfc4122(); + $bitrix24Partner->setOpenLineId($newOpenLineId); + $this->assertEquals($newOpenLineId, $bitrix24Partner->getOpenLineId()); + + $bitrix24Partner->setOpenLineId(null); + $this->assertNull($bitrix24Partner->getOpenLineId()); + + $this->expectException(InvalidArgumentException::class); + /** @phpstan-ignore-next-line */ + $bitrix24Partner->setOpenLineId(''); + } + + /** + * @throws NumberParseException + * @throws InvalidArgumentException + */ + public static function bitrix24PartnerDataProvider(): Generator + { + yield 'partner-status-active-all-fields' => [ + Uuid::v7(), //id + CarbonImmutable::now(), // createdAt + CarbonImmutable::now(), // updatedAt + Bitrix24PartnerStatus::active, + 'Bitrix24 Partner LLC', // title + 12345, // bitrix24 partner id, optional + 'https://bitrix24-partner.com', // site, optional + DemoDataGenerator::getMobilePhone(), // phone, optional + DemoDataGenerator::getEmail(), // email, optional + 'open-line-id', // open line id, optional + Uuid::v7()->toRfc4122(), // externalId, optional + 'comment', // comment, optional + ]; + } +} \ No newline at end of file diff --git a/tests/Application/Contracts/Bitrix24Partners/Repository/Bitrix24PartnerRepositoryInterfaceTest.php b/tests/Application/Contracts/Bitrix24Partners/Repository/Bitrix24PartnerRepositoryInterfaceTest.php new file mode 100644 index 00000000..58f3b93e --- /dev/null +++ b/tests/Application/Contracts/Bitrix24Partners/Repository/Bitrix24PartnerRepositoryInterfaceTest.php @@ -0,0 +1,289 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Application\Contracts\Bitrix24Partners\Repository; + +use Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Entity\Bitrix24PartnerInterface; +use Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Entity\Bitrix24PartnerStatus; +use Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Exceptions\Bitrix24PartnerNotFoundException; +use Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Repository\Bitrix24PartnerRepositoryInterface; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Tests\Builders\DemoDataGenerator; +use Carbon\CarbonImmutable; +use Generator; +use libphonenumber\NumberParseException; +use libphonenumber\PhoneNumber; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; +use Symfony\Component\Uid\Uuid; + +#[CoversClass(Bitrix24PartnerInterface::class)] +abstract class Bitrix24PartnerRepositoryInterfaceTest extends TestCase +{ + abstract protected function createBitrix24PartnerImplementation( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId): Bitrix24PartnerInterface; + + abstract protected function createBitrix24PartnerRepositoryImplementation(): Bitrix24PartnerRepositoryInterface; + + /** + * @throws InvalidArgumentException + * @throws Bitrix24PartnerNotFoundException + */ + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test save method')] + final public function testSave( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $b24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + $b24PartnerRepository = $this->createBitrix24PartnerRepositoryImplementation(); + + $b24PartnerRepository->save($b24Partner); + + $res = $b24PartnerRepository->getById($b24Partner->getId()); + $this->assertEquals($b24Partner, $res); + } + + /** + * @throws InvalidArgumentException + * @throws Bitrix24PartnerNotFoundException + */ + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test save with two bitrix24partner id')] + final public function testSaveWithTwoBitrix24PartnerId( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $b24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + $b24PartnerRepository = $this->createBitrix24PartnerRepositoryImplementation(); + + $b24PartnerRepository->save($b24Partner); + + $res = $b24PartnerRepository->getById($b24Partner->getId()); + $this->assertEquals($b24Partner, $res); + + $secondB24Partner = $this->createBitrix24PartnerImplementation(Uuid::v7(), $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + $this->expectException(InvalidArgumentException::class); + $b24PartnerRepository->save($secondB24Partner); + } + + /** + * @throws InvalidArgumentException + * @throws Bitrix24PartnerNotFoundException + */ + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test delete method')] + final public function testDelete( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $b24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + $b24PartnerRepository = $this->createBitrix24PartnerRepositoryImplementation(); + + $b24Partner->markAsDeleted('delete partner'); + $b24PartnerRepository->save($b24Partner); + + $b24PartnerRepository->delete($b24Partner->getId()); + + $this->assertNull($b24PartnerRepository->findByBitrix24PartnerId($bitrix24PartnerId)); + } + + /** + * @throws InvalidArgumentException + * @throws Bitrix24PartnerNotFoundException + */ + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test save method')] + final public function testGetById( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $b24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + $b24PartnerRepository = $this->createBitrix24PartnerRepositoryImplementation(); + + $b24PartnerRepository->save($b24Partner); + + $res = $b24PartnerRepository->getById($b24Partner->getId()); + $this->assertEquals($b24Partner, $res); + + $this->expectException(Bitrix24PartnerNotFoundException::class); + $b24PartnerRepository->getById(Uuid::v7()); + } + + /** + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test findByBitrix24PartnerId method')] + final public function testFindByBitrix24PartnerId( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $b24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + $b24PartnerRepository = $this->createBitrix24PartnerRepositoryImplementation(); + + $b24PartnerRepository->save($b24Partner); + + $res = $b24PartnerRepository->findByBitrix24PartnerId($b24Partner->getBitrix24PartnerId()); + $this->assertEquals($b24Partner, $res); + + + $this->assertNull($b24PartnerRepository->findByBitrix24PartnerId(0)); + } + + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test findByTitle method')] + final public function testFindByTitle( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $b24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + $b24PartnerRepository = $this->createBitrix24PartnerRepositoryImplementation(); + + $b24PartnerRepository->save($b24Partner); + + $res = $b24PartnerRepository->findByTitle($b24Partner->getTitle()); + $this->assertEquals($b24Partner, $res[0]); + + $this->assertEmpty($b24PartnerRepository->findByTitle('test')); + } + + #[Test] + #[DataProvider('bitrix24PartnerDataProvider')] + #[TestDox('test findByExternalId method')] + final public function testFindByExternalId( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId + ): void + { + $b24Partner = $this->createBitrix24PartnerImplementation($uuid, $createdAt, $updatedAt, $bitrix24PartnerStatus, $title, $bitrix24PartnerId, $site, $phoneNumber, $email, $openLineId, $externalId); + $b24PartnerRepository = $this->createBitrix24PartnerRepositoryImplementation(); + + $b24PartnerRepository->save($b24Partner); + + $res = $b24PartnerRepository->findByExternalId($b24Partner->getExternalId()); + $this->assertEquals($b24Partner, $res[0]); + + $this->assertEmpty($b24PartnerRepository->findByExternalId('test')); + } + + /** + * @throws NumberParseException + * @throws InvalidArgumentException + */ + public static function bitrix24PartnerDataProvider(): Generator + { + yield 'partner-status-active-all-fields' => [ + Uuid::v7(), //id + CarbonImmutable::now(), // createdAt + CarbonImmutable::now(), // updatedAt + Bitrix24PartnerStatus::active, + 'Bitrix24 Partner LLC', // title + 12345, // bitrix24 partner id, optional + 'https://bitrix24-partner.com', // site, optional + DemoDataGenerator::getMobilePhone(), // phone, optional + DemoDataGenerator::getEmail(), // email, optional + 'open-line-id', // open line id, optional + Uuid::v7()->toRfc4122(), // externalId, optional + 'comment', // comment, optional + ]; + } +} \ No newline at end of file diff --git a/tests/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceTest.php b/tests/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceTest.php new file mode 100644 index 00000000..dab78765 --- /dev/null +++ b/tests/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceTest.php @@ -0,0 +1,960 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Application\Contracts\ContactPersons\Entity; + +use Bitrix24\SDK\Application\Contracts\ContactPersons\Entity\ContactPersonInterface; +use Bitrix24\SDK\Application\Contracts\ContactPersons\Entity\ContactPersonStatus; +use Bitrix24\SDK\Application\Contracts\ContactPersons\Entity\FullName; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Tests\Builders\DemoDataGenerator; +use Carbon\CarbonImmutable; +use Darsyn\IP\Version\Multi as IP; +use Generator; +use libphonenumber\PhoneNumber; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; +use Symfony\Component\Uid\Uuid; + +#[CoversClass(ContactPersonInterface::class)] +abstract class ContactPersonInterfaceTest extends TestCase +{ + abstract protected function createContactPersonImplementation( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): ContactPersonInterface; + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test getId method')] + final public function testGetId( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($uuid, $contactPerson->getId()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test getStatus method')] + final public function testGetStatus( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($contactPersonStatus, $contactPerson->getStatus()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test markAsActive method')] + final public function testMarkAsActive( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson->markAsBlocked('block contact person'); + $this->assertEquals(ContactPersonStatus::blocked, $contactPerson->getStatus()); + $message = 'unblock contact person'; + $contactPerson->markAsActive($message); + $this->assertEquals(ContactPersonStatus::active, $contactPerson->getStatus()); + $this->assertEquals($message, $contactPerson->getComment()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test markAsBlocked method')] + final public function testMarkAsBlocked( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $message = 'block contact person'; + $contactPerson->markAsBlocked($message); + $this->assertEquals(ContactPersonStatus::blocked, $contactPerson->getStatus()); + $this->assertEquals($message, $contactPerson->getComment()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test markAsDeleted method')] + final public function testMarkAsDeleted( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $message = 'soft delete contact person'; + $contactPerson->markAsDeleted($message); + $this->assertEquals(ContactPersonStatus::deleted, $contactPerson->getStatus()); + $this->assertEquals($message, $contactPerson->getComment()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test markAsDeleted method for blocked account')] + final public function testMarkAsDeletedBlockedAccount( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $message = 'block contact person'; + $contactPerson->markAsBlocked($message); + $this->assertEquals(ContactPersonStatus::blocked, $contactPerson->getStatus()); + $this->assertEquals($message, $contactPerson->getComment()); + $message = 'delete contact person'; + $contactPerson->markAsDeleted($message); + $this->assertEquals(ContactPersonStatus::deleted, $contactPerson->getStatus()); + $this->assertEquals($message, $contactPerson->getComment()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test markAsDeleted method')] + final public function testMarkAsDeletedDeletedAccount( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $message = 'soft delete contact person'; + $contactPerson->markAsDeleted($message); + $this->expectException(InvalidArgumentException::class); + $contactPerson->markAsDeleted($message); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test getFullName method')] + final public function testGetFullName( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals(new FullName($name, $surname, $patronymic), $contactPerson->getFullName()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test changeFullName method')] + final public function testChangeFullName( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $newFullName = DemoDataGenerator::getFullName(); + $contactPerson->changeFullName($newFullName); + $this->assertEquals($newFullName, $contactPerson->getFullName()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test getUpdatedAt method')] + final public function testGetUpdatedAt( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson->markAsBlocked('test block'); + $this->assertEquals($createdAt, $contactPerson->getCreatedAt()); + $this->assertNotEquals($updatedAt, $contactPerson->getUpdatedAt()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test getCreatedAt method')] + final public function testCreatedAt( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($createdAt, $contactPerson->getCreatedAt()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test getEmail method')] + final public function testGetEmail( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($email, $contactPerson->getEmail()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test changeEmail method')] + final public function testChangeEmail( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + + $newEmail = DemoDataGenerator::getEmail(); + $contactPerson->changeEmail($newEmail); + $this->assertEquals($newEmail, $contactPerson->getEmail()); + $this->assertNull($contactPerson->getEmailVerifiedAt()); + + $newEmail = DemoDataGenerator::getEmail(); + $contactPerson->changeEmail($newEmail, true); + $this->assertEquals($newEmail, $contactPerson->getEmail()); + $this->assertNotNull($contactPerson->getEmailVerifiedAt()); + $newEmail = DemoDataGenerator::getEmail(); + $contactPerson->changeEmail($newEmail); + $this->assertEquals($newEmail, $contactPerson->getEmail()); + $this->assertNull($contactPerson->getEmailVerifiedAt()); + + $newEmail = DemoDataGenerator::getEmail(); + $contactPerson->changeEmail($newEmail, false); + $this->assertEquals($newEmail, $contactPerson->getEmail()); + $this->assertNull($contactPerson->getEmailVerifiedAt()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test markEmailAsVerified method')] + final public function testMarkEmailAsVerified( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + + $newEmail = DemoDataGenerator::getEmail(); + // email not verified + $contactPerson->changeEmail($newEmail); + $this->assertNull($contactPerson->getEmailVerifiedAt()); + + $contactPerson->markEmailAsVerified(); + $this->assertNotNull($contactPerson->getEmailVerifiedAt()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test getMobilePhone method')] + final public function testGetMobilePhone( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($phoneNumber, $contactPerson->getMobilePhone()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test changeMobilePhone method')] + final public function testChangeMobilePhone( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + + $phone = DemoDataGenerator::getMobilePhone(); + $contactPerson->changeMobilePhone($phone); + $this->assertNull($contactPerson->getMobilePhoneVerifiedAt()); + + $phone = DemoDataGenerator::getMobilePhone(); + $contactPerson->changeMobilePhone($phone, false); + $this->assertNull($contactPerson->getMobilePhoneVerifiedAt()); + + $phone = DemoDataGenerator::getMobilePhone(); + $contactPerson->changeMobilePhone($phone, true); + $this->assertNotNull($contactPerson->getMobilePhoneVerifiedAt()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test getMobilePhoneVerifiedAt method')] + final public function testGetMobilePhoneVerifiedAt( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($phoneNumber, $contactPerson->getMobilePhone()); + + $phone = DemoDataGenerator::getMobilePhone(); + $contactPerson->changeMobilePhone($phone, true); + $this->assertNotNull($contactPerson->getMobilePhoneVerifiedAt()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test markMobilePhoneAsVerified method')] + final public function testMarkMobilePhoneAsVerified( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($phoneNumber, $contactPerson->getMobilePhone()); + + $phone = DemoDataGenerator::getMobilePhone(); + $contactPerson->changeMobilePhone($phone); + $this->assertNull($contactPerson->getMobilePhoneVerifiedAt()); + $contactPerson->markMobilePhoneAsVerified(); + $this->assertNotNull($contactPerson->getMobilePhoneVerifiedAt()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test getComment method')] + final public function testGetComment( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $comment = 'block reason'; + $contactPerson->markAsBlocked($comment); + $this->assertEquals($comment, $contactPerson->getComment()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test setExternalId method')] + final public function testSetExternalId( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $uuidV7 = Uuid::v7(); + + $contactPerson->setExternalId($uuidV7->toRfc4122()); + $this->assertEquals($uuidV7->toRfc4122(), $contactPerson->getExternalId()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test getExternalId method')] + final public function testGetExternalId( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $externalId = null; + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertNull($contactPerson->getExternalId()); + + $uuidV7 = Uuid::v7(); + $externalId = $uuidV7->toRfc4122(); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($externalId, $contactPerson->getExternalId()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test getBitrix24UserId method')] + final public function testGetBitrix24UserId( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $bitrix24UserId = null; + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertNull($contactPerson->getBitrix24UserId()); + + $bitrix24UserId = random_int(1, 100); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($bitrix24UserId, $contactPerson->getBitrix24UserId()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test getBitrix24PartnerId method with happy path')] + final public function testGetBitrix24PartnerId( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + if ($bitrix24PartnerUuid === null) { + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertNull($contactPerson->getBitrix24PartnerId()); + } else { + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($bitrix24PartnerUuid, $contactPerson->getBitrix24PartnerId()); + } + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test setBitrix24PartnerId method with happy path')] + final public function testSetBitrix24PartnerId( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + if ($bitrix24PartnerUuid === null) { + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertNull($contactPerson->getBitrix24PartnerId()); + + $bitrix24PartnerUuid = Uuid::v7(); + $contactPerson->setBitrix24PartnerId($bitrix24PartnerUuid); + $this->assertEquals($bitrix24PartnerUuid, $contactPerson->getBitrix24PartnerId()); + } else { + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($bitrix24PartnerUuid, $contactPerson->getBitrix24PartnerId()); + $contactPerson->setBitrix24PartnerId(null); + $this->assertNull($contactPerson->getBitrix24PartnerId()); + } + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test getUserAgent method')] + final public function testGetUserAgent( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($userAgent, $contactPerson->getUserAgent()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test getUserAgentReferer method')] + final public function testGetUserAgentReferer( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($userAgentReferer, $contactPerson->getUserAgentReferer()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test getUserAgentIp method')] + final public function testGetUserAgentIp( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($userAgentIp, $contactPerson->getUserAgentIp()); + } + + public static function contactPersonDataProvider(): Generator + { + $fullName = DemoDataGenerator::getFullName(); + + yield 'valid-all-fields-by-default' => [ + Uuid::v7(), + CarbonImmutable::now(), + CarbonImmutable::now(), + ContactPersonStatus::active, + $fullName->name, + $fullName->surname, + $fullName->patronymic, + DemoDataGenerator::getEmail(), + CarbonImmutable::now(), + 'comment', + DemoDataGenerator::getMobilePhone(), + CarbonImmutable::now(), + null, + null, + null, + DemoDataGenerator::getUserAgent(), + 'https://bitrix24.com/apps/store?utm_source=bx24', + DemoDataGenerator::getUserAgentIp() + ]; + yield 'contact-person-is-partner-employee' => [ + Uuid::v7(), + CarbonImmutable::now(), + CarbonImmutable::now(), + ContactPersonStatus::active, + $fullName->name, + $fullName->surname, + $fullName->patronymic, + DemoDataGenerator::getEmail(), + CarbonImmutable::now(), + 'comment', + DemoDataGenerator::getMobilePhone(), + CarbonImmutable::now(), + null, + null, + Uuid::v7(), + DemoDataGenerator::getUserAgent(), + 'https://bitrix24.com/apps/store?utm_source=bx24', + DemoDataGenerator::getUserAgentIp() + ]; + } +} \ No newline at end of file diff --git a/tests/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php b/tests/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php new file mode 100644 index 00000000..66ec443a --- /dev/null +++ b/tests/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php @@ -0,0 +1,671 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Application\Contracts\ContactPersons\Repository; + +use Bitrix24\SDK\Application\Contracts\ContactPersons\Entity\ContactPersonInterface; +use Bitrix24\SDK\Application\Contracts\ContactPersons\Entity\ContactPersonStatus; +use Bitrix24\SDK\Application\Contracts\ContactPersons\Exceptions\ContactPersonNotFoundException; +use Bitrix24\SDK\Application\Contracts\ContactPersons\Repository\ContactPersonRepositoryInterface; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Tests\Builders\DemoDataGenerator; +use Carbon\CarbonImmutable; +use Darsyn\IP\Version\Multi as IP; +use Generator; +use libphonenumber\PhoneNumber; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; +use Symfony\Component\Uid\Uuid; + +#[CoversClass(ContactPersonRepositoryInterface::class)] +abstract class ContactPersonRepositoryInterfaceTest extends TestCase +{ + abstract protected function createContactPersonImplementation( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): ContactPersonInterface; + + abstract protected function createContactPersonRepositoryImplementation(): ContactPersonRepositoryInterface; + + /** + * @throws ContactPersonNotFoundException + */ + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test save method for install start use case')] + final public function testSave( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPersonRepository = $this->createContactPersonRepositoryImplementation(); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerId, $userAgent, $userAgentReferer, $userAgentIp); + + $contactPersonRepository->save($contactPerson); + $acc = $contactPersonRepository->getById($contactPerson->getId()); + $this->assertEquals($contactPerson, $acc); + } + + /** + * @throws InvalidArgumentException + * @throws ContactPersonNotFoundException + */ + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test delete method with happy path')] + final public function testDelete( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPersonRepository = $this->createContactPersonRepositoryImplementation(); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerId, $userAgent, $userAgentReferer, $userAgentIp); + + $contactPersonRepository->save($contactPerson); + $contactPerson = $contactPersonRepository->getById($contactPerson->getId()); + $contactPerson->markAsDeleted('soft delete account'); + + $contactPersonRepository->delete($contactPerson->getId()); + + $this->expectException(ContactPersonNotFoundException::class); + $contactPersonRepository->getById($contactPerson->getId()); + } + + /** + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test delete method with unsaved element')] + final public function testDeleteWithUnsavedElement( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPersonRepository = $this->createContactPersonRepositoryImplementation(); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerId, $userAgent, $userAgentReferer, $userAgentIp); + $this->expectException(ContactPersonNotFoundException::class); + $contactPersonRepository->delete($contactPerson->getId()); + } + + /** + * @throws ContactPersonNotFoundException + */ + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test getById method with happy path')] + final public function testGetById( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPersonRepository = $this->createContactPersonRepositoryImplementation(); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerId, $userAgent, $userAgentReferer, $userAgentIp); + + $contactPersonRepository->save($contactPerson); + $acc = $contactPersonRepository->getById($contactPerson->getId()); + $this->assertEquals($contactPerson, $acc); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test getById method with non exist id')] + final public function testGetByIdWithNonExist( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPersonRepository = $this->createContactPersonRepositoryImplementation(); + + $this->expectException(ContactPersonNotFoundException::class); + $contactPersonRepository->getById(Uuid::v7()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test find by email with happy path')] + final public function testFindByEmailWithHappyPath( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPersonRepository = $this->createContactPersonRepositoryImplementation(); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerId, $userAgent, $userAgentReferer, $userAgentIp); + + $contactPersonRepository->save($contactPerson); + $contactPersons = $contactPersonRepository->findByEmail($email); + $this->assertEquals($contactPerson, $contactPersons[0]); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test find by email with non exists email')] + final public function testFindByEmailWithNonExistsEmail( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPersonRepository = $this->createContactPersonRepositoryImplementation(); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerId, $userAgent, $userAgentReferer, $userAgentIp); + + $contactPersonRepository->save($contactPerson); + $contactPersons = $contactPersonRepository->findByEmail('this.email.doesnt.exists@b24.com'); + $this->assertEmpty($contactPersons); + } + + #[Test] + #[DataProvider('contactPersonWithDifferentStatusesDataProvider')] + #[TestDox('test find by email with different statuses')] + final public function testFindByEmailWithDifferentStatuses( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPersonRepository = $this->createContactPersonRepositoryImplementation(); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $bitrix24PartnerId, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); + + $contactPersonRepository->save($contactPerson); + $contactPersons = $contactPersonRepository->findByEmail($email, $contactPersonStatus); + $this->assertEquals($contactPerson, $contactPersons[0]); + } + + #[Test] + #[DataProvider('contactPersonManyAccountsDataProvider')] + #[TestDox('test find by email with verified email')] + final public function testFindByEmailWithVerifiedEmail(array $items): void + { + $contactPersonRepository = $this->createContactPersonRepositoryImplementation(); + $expectedContactPerson = null; + foreach ($items as $item) { + [$uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerId, $userAgent, $userAgentReferer, $userAgentIp] = $item; + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPersonRepository->save($contactPerson); + if (!$expectedContactPerson instanceof ContactPersonInterface) { + $expectedContactPerson = $contactPerson; + } + } + + $result = $contactPersonRepository->findByEmail($expectedContactPerson->getEmail(), null, true); + $this->assertCount(1, $result); + $this->assertEquals($expectedContactPerson, $result[0]); + + } + + #[Test] + #[DataProvider('contactPersonManyAccountsDataProvider')] + #[TestDox('test find by phone with verified phone')] + final public function testFindByEmailWithVerifiedPhone(array $items): void + { + $contactPersonRepository = $this->createContactPersonRepositoryImplementation(); + $expectedContactPerson = null; + foreach ($items as $item) { + [$uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerId, $userAgent, $userAgentReferer, $userAgentIp] = $item; + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPersonRepository->save($contactPerson); + if (!$expectedContactPerson instanceof ContactPersonInterface) { + $expectedContactPerson = $contactPerson; + } + } + + $result = $contactPersonRepository->findByPhone($expectedContactPerson->getMobilePhone(), null, true); + $this->assertCount(1, $result); + $this->assertEquals($expectedContactPerson, $result[0]); + + } + + /** + * @throws ContactPersonNotFoundException + */ + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test findByExternalId method with happy path')] + final public function testFindByExternalId( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPersonRepository = $this->createContactPersonRepositoryImplementation(); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerId, $userAgent, $userAgentReferer, $userAgentIp); + + $externalId = Uuid::v7(); + $contactPerson->setExternalId($externalId->toRfc4122()); + + $contactPersonRepository->save($contactPerson); + $acc = $contactPersonRepository->findByExternalId($externalId->toRfc4122()); + $this->assertEquals($contactPerson, $acc[0]); + } + + /** + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test findByExternalId with non exist id')] + final public function testFindByExternalIdWithNonExistsId( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPersonRepository = $this->createContactPersonRepositoryImplementation(); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerId, $userAgent, $userAgentReferer, $userAgentIp); + + $contactPersonRepository->save($contactPerson); + $this->assertEquals([], $contactPersonRepository->findByExternalId(Uuid::v7()->toRfc4122())); + } + + /** + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test findByExternalId with empty id')] + final public function testFindByExternalIdWithEmptyId( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPersonRepository = $this->createContactPersonRepositoryImplementation(); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerId, $userAgent, $userAgentReferer, $userAgentIp); + + $contactPersonRepository->save($contactPerson); + $this->expectException(InvalidArgumentException::class); + /** @phpstan-ignore-next-line */ + $contactPersonRepository->findByExternalId(''); + } + + #[Test] + #[DataProvider('contactPersonManyAccountsDataProvider')] + #[TestDox('test findByExternalId with multiple installs by same contact person')] + final public function testFindByExternalIdWithMultipleInstalls(array $items): void + { + $contactPersonRepository = $this->createContactPersonRepositoryImplementation(); + $expectedContactPersons = []; + $expectedExternalId = null; + foreach ($items as $item) { + [$uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerId, $userAgent, $userAgentReferer, $userAgentIp] = $item; + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $bitrix24PartnerId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPersonRepository->save($contactPerson); + if ($contactPerson->getExternalId() !== null) { + $expectedContactPersons[] = $contactPerson; + if ($expectedExternalId === null) { + $expectedExternalId = $contactPerson->getExternalId(); + } + } + } + + $result = $contactPersonRepository->findByExternalId($expectedExternalId); + $this->assertCount(2, $result); + $this->assertEquals($expectedContactPersons, $result); + + } + + public static function contactPersonManyAccountsDataProvider(): Generator + { + $fullName = DemoDataGenerator::getFullName(); + $externalId = Uuid::v7()->toRfc4122(); + yield 'many accounts with one verified email' => + [ + [ + [ + Uuid::v7(), + CarbonImmutable::now(), + CarbonImmutable::now(), + ContactPersonStatus::active, + $fullName->name, + $fullName->surname, + $fullName->patronymic, + DemoDataGenerator::getEmail(), + CarbonImmutable::now(), + 'comment', + DemoDataGenerator::getMobilePhone(), + CarbonImmutable::now(), + null, + null, + null, + DemoDataGenerator::getUserAgent(), + 'https://bitrix24.com/apps/store?utm_source=bx24', + DemoDataGenerator::getUserAgentIp() + ], + [ + Uuid::v7(), + CarbonImmutable::now(), + CarbonImmutable::now(), + ContactPersonStatus::active, + $fullName->name, + $fullName->surname, + $fullName->patronymic, + DemoDataGenerator::getEmail(), + null, + 'comment', + DemoDataGenerator::getMobilePhone(), + null, + $externalId, + null, + null, + DemoDataGenerator::getUserAgent(), + 'https://bitrix24.com/apps/store?utm_source=bx24', + DemoDataGenerator::getUserAgentIp() + ], + [ + Uuid::v7(), + CarbonImmutable::now(), + CarbonImmutable::now(), + ContactPersonStatus::active, + $fullName->name, + $fullName->surname, + $fullName->patronymic, + DemoDataGenerator::getEmail(), + null, + 'comment', + DemoDataGenerator::getMobilePhone(), + null, + $externalId, + null, + null, + DemoDataGenerator::getUserAgent(), + 'https://bitrix24.com/apps/store?utm_source=bx24', + DemoDataGenerator::getUserAgentIp() + ] + ] + ]; + } + + public static function contactPersonDataProvider(): Generator + { + $fullName = DemoDataGenerator::getFullName(); + + yield 'valid-all-fields-by-default' => [ + Uuid::v7(), + CarbonImmutable::now(), + CarbonImmutable::now(), + ContactPersonStatus::active, + $fullName->name, + $fullName->surname, + $fullName->patronymic, + DemoDataGenerator::getEmail(), + CarbonImmutable::now(), + 'comment', + DemoDataGenerator::getMobilePhone(), + CarbonImmutable::now(), + null, + null, + null, + DemoDataGenerator::getUserAgent(), + 'https://bitrix24.com/apps/store?utm_source=bx24', + DemoDataGenerator::getUserAgentIp() + ]; + } + + public static function contactPersonWithDifferentStatusesDataProvider(): Generator + { + $fullName = DemoDataGenerator::getFullName(); + + yield 'active' => [ + Uuid::v7(), + CarbonImmutable::now(), + CarbonImmutable::now(), + ContactPersonStatus::active, + $fullName->name, + $fullName->surname, + $fullName->patronymic, + DemoDataGenerator::getEmail(), + CarbonImmutable::now(), + 'comment', + DemoDataGenerator::getMobilePhone(), + CarbonImmutable::now(), + null, + null, + null, + DemoDataGenerator::getUserAgent(), + 'https://bitrix24.com/apps/store?utm_source=bx24', + DemoDataGenerator::getUserAgentIp() + ]; + + yield 'blocked' => [ + Uuid::v7(), + CarbonImmutable::now(), + CarbonImmutable::now(), + ContactPersonStatus::blocked, + $fullName->name, + $fullName->surname, + $fullName->patronymic, + DemoDataGenerator::getEmail(), + CarbonImmutable::now(), + 'comment', + DemoDataGenerator::getMobilePhone(), + CarbonImmutable::now(), + null, + null, + null, + DemoDataGenerator::getUserAgent(), + 'https://bitrix24.com/apps/store?utm_source=bx24', + DemoDataGenerator::getUserAgentIp() + ]; + + yield 'deleted' => [ + Uuid::v7(), + CarbonImmutable::now(), + CarbonImmutable::now(), + ContactPersonStatus::deleted, + $fullName->name, + $fullName->surname, + $fullName->patronymic, + DemoDataGenerator::getEmail(), + CarbonImmutable::now(), + 'comment', + DemoDataGenerator::getMobilePhone(), + CarbonImmutable::now(), + null, + null, + null, + DemoDataGenerator::getUserAgent(), + 'https://bitrix24.com/apps/store?utm_source=bx24', + DemoDataGenerator::getUserAgentIp() + ]; + } +} \ No newline at end of file diff --git a/tests/ApplicationBridge/.env b/tests/ApplicationBridge/.env new file mode 100644 index 00000000..a15fc445 --- /dev/null +++ b/tests/ApplicationBridge/.env @@ -0,0 +1,9 @@ +# monolog +LOGS_LEVEL=100 +LOGS_FILE_NAME=bitrix24-php-sdk.log + +# local application secret parameters +BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID= +BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET= +BITRIX24_PHP_SDK_APPLICATION_SCOPE= +BITRIX24_PHP_SDK_APPLICATION_DOMAIN_URL= \ No newline at end of file diff --git a/tests/ApplicationBridge/ApplicationCredentialsProvider.php b/tests/ApplicationBridge/ApplicationCredentialsProvider.php new file mode 100644 index 00000000..0524e7fe --- /dev/null +++ b/tests/ApplicationBridge/ApplicationCredentialsProvider.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\ApplicationBridge; + + +use Bitrix24\SDK\Core\Credentials\AuthToken; +use Bitrix24\SDK\Core\Credentials\ApplicationProfile; +use Bitrix24\SDK\Core\Credentials\Credentials; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Events\AuthTokenRenewedEvent; +use JetBrains\PhpStorm\NoReturn; +use Symfony\Component\Filesystem\Filesystem; + +readonly class ApplicationCredentialsProvider +{ + public function __construct(private AuthTokenRepositoryInterface $repository) + { + } + + public function isCredentialsAvailable(): bool + { + return $this->repository->isAvailable(); + } + + public function saveAuthToken(AuthToken $authToken): void + { + $this->repository->saveToken($authToken); + } + + /** + * @throws InvalidArgumentException + */ + public function getCredentials(ApplicationProfile $applicationProfile, string $domainUrl): Credentials + { + return new Credentials( + null, + $this->repository->getToken(), + $applicationProfile, + $domainUrl + ); + } + + #[NoReturn] + public function onAuthTokenRenewedEventListener(AuthTokenRenewedEvent $event): void + { + // update credentials + $this->repository->saveRenewedToken($event->getRenewedToken()); + } + + public static function buildProviderForLocalApplication(): self + { + return new ApplicationCredentialsProvider(new AuthTokenFileStorage(new Filesystem())); + } +} \ No newline at end of file diff --git a/tests/ApplicationBridge/AuthTokenFileStorage.php b/tests/ApplicationBridge/AuthTokenFileStorage.php new file mode 100644 index 00000000..787324de --- /dev/null +++ b/tests/ApplicationBridge/AuthTokenFileStorage.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\ApplicationBridge; + +use Bitrix24\SDK\Core\Credentials\AuthToken; +use Bitrix24\SDK\Core\Exceptions\FileNotFoundException; +use Bitrix24\SDK\Core\Response\DTO\RenewedAuthToken; +use JsonException; +use Symfony\Component\Filesystem\Filesystem; + +readonly class AuthTokenFileStorage implements AuthTokenRepositoryInterface +{ + private const TOKEN_FILE_NAME = 'auth.json'; + + public function __construct( + private Filesystem $filesystem) + { + } + + private function getFileName(): string + { + return dirname(__DIR__, 2) . '/tests/ApplicationBridge/' . self::TOKEN_FILE_NAME; + } + + public function isAvailable(): bool + { + return $this->filesystem->exists($this->getFileName()); + } + + /** + * @throws FileNotFoundException + * @throws JsonException + */ + public function getToken(): AuthToken + { + if (!$this->filesystem->exists($this->getFileName())) { + throw new FileNotFoundException(sprintf('file «%s» with stored access token not found', $this->getFileName())); + } + + $payload = file_get_contents($this->getFileName()); + return AuthToken::initFromArray(json_decode($payload, true, 512, JSON_THROW_ON_ERROR)); + } + + /** + * @throws JsonException + */ + public function saveToken(AuthToken $authToken): void + { + $tokenPayload = json_encode([ + 'access_token' => $authToken->getAccessToken(), + 'refresh_token' => $authToken->getRefreshToken(), + 'expires' => $authToken->getExpires() + ], JSON_THROW_ON_ERROR); + + $this->filesystem->dumpFile($this->getFileName(), $tokenPayload); + } + + public function saveRenewedToken(RenewedAuthToken $renewedAuthToken): void + { + $this->saveToken($renewedAuthToken->authToken); + } +} \ No newline at end of file diff --git a/tests/ApplicationBridge/AuthTokenRepositoryInterface.php b/tests/ApplicationBridge/AuthTokenRepositoryInterface.php new file mode 100644 index 00000000..fa1389d9 --- /dev/null +++ b/tests/ApplicationBridge/AuthTokenRepositoryInterface.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\ApplicationBridge; + + +use Bitrix24\SDK\Core\Credentials\AuthToken; +use Bitrix24\SDK\Core\Response\DTO\RenewedAuthToken; + +interface AuthTokenRepositoryInterface +{ + public function getToken(): AuthToken; + + public function saveRenewedToken(RenewedAuthToken $renewedAuthToken): void; + + public function saveToken(AuthToken $authToken): void; + + public function isAvailable():bool; +} \ No newline at end of file diff --git a/tests/ApplicationBridge/index.php b/tests/ApplicationBridge/index.php new file mode 100644 index 00000000..69093196 --- /dev/null +++ b/tests/ApplicationBridge/index.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +use Bitrix24\SDK\Core\Credentials\AuthToken; +use Bitrix24\SDK\Core\Credentials\ApplicationProfile; +use Bitrix24\SDK\Services\ServiceBuilderFactory; +use Bitrix24\SDK\Tests\ApplicationBridge\ApplicationCredentialsProvider; +use Monolog\Handler\StreamHandler; +use Monolog\Logger; +use Monolog\Processor\MemoryUsageProcessor; +use Symfony\Component\Dotenv\Dotenv; +use Symfony\Component\ErrorHandler\Debug; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\HttpFoundation\Request; + +require dirname(__DIR__, 2) . '/vendor/autoload.php'; + +?> +
+
+    
+    
+bootEnv('.env'); + +if ($_SERVER['APP_DEBUG']) { + umask(0000); + + if (class_exists( + Debug::class + )) { + Debug::enable(); + } +} + +$request = Request::createFromGlobals(); + + +$log = new Logger('bitrix24-php-sdk'); +$log->pushHandler(new StreamHandler($_ENV['LOGS_FILE_NAME'], (int)$_ENV['LOGS_LEVEL'])); +$log->pushProcessor(new MemoryUsageProcessor(true, true)); + +$b24ServiceFactory = new ServiceBuilderFactory(new EventDispatcher(), $log); +$appProfile = ApplicationProfile::initFromArray($_ENV); +$accessToken = AuthToken::initFromPlacementRequest($request); +$b24Service = $b24ServiceFactory->initFromRequest($appProfile, $accessToken, $_REQUEST['DOMAIN']); + +// save new access token for integration tests +$credentialsProvider = ApplicationCredentialsProvider::buildProviderForLocalApplication(); +$credentialsProvider->saveAuthToken($accessToken); + +// call rest-api +print_r($b24Service->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()); + diff --git a/tests/ApplicationBridge/install.php b/tests/ApplicationBridge/install.php new file mode 100644 index 00000000..5ca9c29f --- /dev/null +++ b/tests/ApplicationBridge/install.php @@ -0,0 +1,12 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ +?> + + \ No newline at end of file diff --git a/tests/Builders/DemoDataGenerator.php b/tests/Builders/DemoDataGenerator.php new file mode 100644 index 00000000..b95a5763 --- /dev/null +++ b/tests/Builders/DemoDataGenerator.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Tests\Builders; + +use Bitrix24\SDK\Application\Contracts\ContactPersons\Entity\FullName; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Darsyn\IP\Version\Multi; +use Faker; +use libphonenumber\NumberParseException; +use libphonenumber\PhoneNumber; +use libphonenumber\PhoneNumberUtil; +use Money\Currency; +use Money\Money; +use Random\RandomException; + +class DemoDataGenerator +{ + /** + * @throws InvalidArgumentException|NumberParseException + */ + public static function getMobilePhone(): PhoneNumber + { + $num = PhoneNumberUtil::getInstance()->parse(Faker\Factory::create()->phoneNumber(), 'US'); + if ($num === null) { + throw new InvalidArgumentException('cannot parse phone number'); + } + return $num; + } + + public static function getRecordFileUrl(): string + { + return 'https://github.com/mesilov/bitrix24-php-sdk/raw/384-update-scope-telephony/tests/Integration/Services/Telephony/call-record-test.mp3'; + } + + public static function getFullName(): FullName + { + $faker = Faker\Factory::create(); + return new FullName($faker->lastName(), $faker->lastName(), $faker->lastName()); + } + + public static function getEmail(): string + { + return Faker\Factory::create()->email(); + } + + public static function getUserAgent(): string + { + return Faker\Factory::create()->userAgent(); + } + + public static function getUserAgentIp(): Multi + { + return Multi::factory(Faker\Factory::create()->ipv4()); + } + + public static function getCurrency(): Currency + { + return new Currency('USD'); + } + + /** + * @throws RandomException + */ + public static function getMoneyAmount(): Money + { + return new Money(random_int(1000, 1000000), self::getCurrency()); + } +} \ No newline at end of file diff --git a/tests/Builders/Services/CRM/PhoneCollectionBuilder.php b/tests/Builders/Services/CRM/PhoneCollectionBuilder.php new file mode 100644 index 00000000..71e4addd --- /dev/null +++ b/tests/Builders/Services/CRM/PhoneCollectionBuilder.php @@ -0,0 +1,101 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Builders\Services\CRM; + +use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\Phone; +use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\PhoneValueType; +use Exception; + +class PhoneCollectionBuilder +{ + /** + * @var Phone[] + */ + private array $phones; + private PhoneNumberBuilder $phoneNumberBuilder; + + public function __construct() + { + $this->phones = []; + $this->phoneNumberBuilder = new PhoneNumberBuilder(); + } + + /** + * @throws Exception + */ + public function withDuplicatePhones(int $duplicatesCount = 1): self + { + $duplicatePhone = $this->phoneNumberBuilder->build(); + + $duplicates = []; + for ($i = 0; $i <= $duplicatesCount; $i++) { + $duplicates[] = new Phone([ + 'ID' => time() + random_int(1, 1000000), + 'VALUE' => $duplicatePhone, + 'VALUE_TYPE' => PhoneValueType::work->value + ]); + } + + $this->phones = array_merge( + [ + new Phone([ + 'ID' => time() + random_int(1, 1000000), + 'VALUE' => $this->phoneNumberBuilder->build(), + 'VALUE_TYPE' => PhoneValueType::work->value + ]) + ], + $duplicates + ); + + return $this; + } + + public function withPhoneLength(int $phoneLength): self + { + $this->phones = [ + new Phone([ + 'ID' => time() + random_int(1, 1000000), + 'VALUE' => $this->phoneNumberBuilder->withLength($phoneLength)->build(), + 'VALUE_TYPE' => PhoneValueType::work->value + ]), + new Phone([ + 'ID' => time() + random_int(1, 1000000), + 'VALUE' => $this->phoneNumberBuilder->withLength(7)->build(), + 'VALUE_TYPE' => PhoneValueType::work->value + ]) + ]; + + return $this; + } + + /** + * @throws Exception + */ + public function build(): array + { + return $this->phones; + } + + public function buildNewPhonesCommand(): array + { + $res = []; + foreach ($this->phones as $phone) { + $res[] = [ + 'VALUE' => $phone->VALUE, + 'VALUE_TYPE' => $phone->VALUE_TYPE->value + ]; + } + return $res; + } +} \ No newline at end of file diff --git a/tests/Builders/Services/CRM/PhoneNumberBuilder.php b/tests/Builders/Services/CRM/PhoneNumberBuilder.php new file mode 100644 index 00000000..62d3eedc --- /dev/null +++ b/tests/Builders/Services/CRM/PhoneNumberBuilder.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Builders\Services\CRM; + +use Exception; + +class PhoneNumberBuilder +{ + private int $length; + + public function __construct() + { + $this->length = 7; + } + + public function withLength(int $length): self + { + $this->length = $length; + return $this; + } + + /** + * @throws Exception + */ + public function build(): string + { + return '+1' . substr((string)time(), 2, $this->length) . substr((string)random_int(1000, PHP_INT_MAX), 0, 3); + } +} \ No newline at end of file diff --git a/tests/CustomAssertions/CustomBitrix24Assertions.php b/tests/CustomAssertions/CustomBitrix24Assertions.php new file mode 100644 index 00000000..5f12030d --- /dev/null +++ b/tests/CustomAssertions/CustomBitrix24Assertions.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +namespace Bitrix24\SDK\Tests\CustomAssertions; + +use Bitrix24\SDK\Services\CRM\Contact\Result\ContactItemResult; +use Typhoon\Reflection\TyphoonReflector; + +trait CustomBitrix24Assertions +{ + /** + * @param array $fieldCodesFromApi + * @param class-string $resultItemClassName + * @return void + */ + protected function assertBitrix24AllResultItemFieldsAnnotated(array $fieldCodesFromApi, string $resultItemClassName): void + { + sort($fieldCodesFromApi); + + // parse keys from phpdoc annotation + $props = TyphoonReflector::build()->reflectClass($resultItemClassName)->properties(); + $propsFromAnnotations = []; + foreach ($props as $meta) { + if ($meta->isAnnotated() && !$meta->isNative()) { + $propsFromAnnotations[] = $meta->id->name; + } + } + sort($propsFromAnnotations); + + $this->assertEquals($fieldCodesFromApi, $propsFromAnnotations, + sprintf('in phpdocs annotations for class %s we not found fields from actual api response: %s', + $resultItemClassName, + implode(', ', array_values(array_diff($fieldCodesFromApi, $propsFromAnnotations))) + )); + } +} \ No newline at end of file diff --git a/tests/Integration/Core/BatchGetTraversableTest.php b/tests/Integration/Core/BatchGetTraversableTest.php new file mode 100644 index 00000000..70f8fa20 --- /dev/null +++ b/tests/Integration/Core/BatchGetTraversableTest.php @@ -0,0 +1,178 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Core; + +use Bitrix24\SDK\Core\Batch; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Services\ServiceBuilder; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; +use Symfony\Component\Uid\Uuid; + +#[CoversClass(Batch::class)] +class BatchGetTraversableTest extends TestCase +{ + private Batch $batch; + private ServiceBuilder $serviceBuilder; + private array $createdContactIds; + + #[TestDox('test get contacts in batch mode with more than one page but only one batch query')] + public function testSingleBatchWithMoreThanOnePage(): void + { + $greaterThanDefaultPageSize = 120; + $originatorId = Uuid::v7()->toRfc4122(); + // add contacts + $contacts = []; + for ($i = 0; $i < $greaterThanDefaultPageSize; $i++) { + $contacts[] = [ + 'fields' => [ + 'NAME' => 'name-' . $i, + 'ORIGINATOR_ID' => $originatorId + ] + ]; + } + $cnt = 0; + foreach ($this->batch->addEntityItems('crm.contact.add', $contacts) as $addedContactResult) { + $this->createdContactIds[] = $addedContactResult->getResult()[0]; + $cnt++; + } + $this->assertEquals(count($contacts), $cnt); + $this->assertEquals(count($contacts), $this->serviceBuilder->getCRMScope()->contact()->countByFilter([ + 'ORIGINATOR_ID' => $originatorId + ])); + + $readContactsId = []; + foreach ($this->batch->getTraversableList('crm.contact.list', + [], + [ + 'ORIGINATOR_ID' => $originatorId + ], + [ + 'ID', + 'NAME', + 'ORIGINATOR_ID' + ] + ) as $cnt => $itemContact) { + $readContactsId[] = $itemContact['ID']; + } + $this->assertEquals($this->createdContactIds, $readContactsId); + } + + #[TestDox('test get contacts in batch mode with more than one page but only one batch query and limit argument')] + public function testSingleBatchWithMoreThanOnePageAndLimit(): void + { + $greaterThanDefaultPageSize = 120; + $originatorId = Uuid::v7()->toRfc4122(); + // add contacts + $contacts = []; + for ($i = 0; $i < $greaterThanDefaultPageSize; $i++) { + $contacts[] = [ + 'fields' => [ + 'NAME' => 'name-' . $i, + 'ORIGINATOR_ID' => $originatorId + ] + ]; + } + $cnt = 0; + foreach ($this->batch->addEntityItems('crm.contact.add', $contacts) as $addedContactResult) { + $this->createdContactIds[] = $addedContactResult->getResult()[0]; + $cnt++; + } + $this->assertEquals(count($contacts), $cnt); + $this->assertEquals(count($contacts), $this->serviceBuilder->getCRMScope()->contact()->countByFilter([ + 'ORIGINATOR_ID' => $originatorId + ])); + + // test batch with limit + $readContactsId = []; + foreach ($this->batch->getTraversableList('crm.contact.list', + [], + [ + 'ORIGINATOR_ID' => $originatorId + ], + [ + 'ID', + 'NAME', + 'ORIGINATOR_ID' + ], + $greaterThanDefaultPageSize / 2 + ) as $cnt => $itemContact) { + $readContactsId[] = $itemContact['ID']; + } + $this->assertCount($greaterThanDefaultPageSize / 2, $readContactsId); + } + + #[TestDox('test get contacts in batch mode with less than one page but only one batch query and limit argument')] + public function testSingleBatchWithLessThanOnePageAndLimit(): void + { + $greaterThanDefaultPageSize = 40; + $originatorId = Uuid::v7()->toRfc4122(); + // add contacts + $contacts = []; + for ($i = 0; $i < $greaterThanDefaultPageSize; $i++) { + $contacts[] = [ + 'fields' => [ + 'NAME' => 'name-' . $i, + 'ORIGINATOR_ID' => $originatorId + ] + ]; + } + $cnt = 0; + foreach ($this->batch->addEntityItems('crm.contact.add', $contacts) as $addedContactResult) { + $this->createdContactIds[] = $addedContactResult->getResult()[0]; + $cnt++; + } + $this->assertEquals(count($contacts), $cnt); + $this->assertEquals(count($contacts), $this->serviceBuilder->getCRMScope()->contact()->countByFilter([ + 'ORIGINATOR_ID' => $originatorId + ])); + + // test batch with limit + $readContactsId = []; + foreach ($this->batch->getTraversableList('crm.contact.list', + [], + [ + 'ORIGINATOR_ID' => $originatorId + ], + [ + 'ID', + 'NAME', + 'ORIGINATOR_ID' + ], + $greaterThanDefaultPageSize / 2 + ) as $cnt => $itemContact) { + $readContactsId[] = $itemContact['ID']; + } + $this->assertCount($greaterThanDefaultPageSize / 2, $readContactsId); + } + + /** + * @throws InvalidArgumentException + */ + public function setUp(): void + { + $this->batch = Fabric::getBatchService(); + $this->serviceBuilder = Fabric::getServiceBuilder(); + } + + public function tearDown(): void + { + if ($this->createdContactIds !== null) { + foreach ($this->batch->deleteEntityItems('crm.contact.delete', $this->createdContactIds) as $result) { + } + } + } +} \ No newline at end of file diff --git a/tests/Integration/Core/BatchTest.php b/tests/Integration/Core/BatchTest.php new file mode 100644 index 00000000..42c66ba0 --- /dev/null +++ b/tests/Integration/Core/BatchTest.php @@ -0,0 +1,383 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Core; + +use Bitrix24\SDK\Core\Batch; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Services\ServiceBuilder; +use Bitrix24\SDK\Tests\Builders\DemoDataGenerator; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\TestCase; +use Symfony\Component\Stopwatch\Stopwatch; + +class BatchTest extends TestCase +{ + private Batch $batch; + private ServiceBuilder $serviceBuilder; + private Stopwatch $stopwatch; + private const DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE = 35; + private const DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_PAGE_SIZE = 65; + private const LIMIT_ELEMENTS_IN_RESULT = 10; + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Exception + * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + * @covers \Bitrix24\SDK\Core\Batch::getTraversableList + * @testdox Get traversable list items in batch mode with more than max batch page count elements + */ + public function testGetTraversableListWithMoreThanMaxBatchPageCountWithoutLimit(): void + { + // prepare demo data + $contactId = $this->serviceBuilder->getCRMScope()->contact()->add( + [ + 'NAME' => sprintf('first_%s', time()), + 'SECOND' => sprintf('second_%s', time()), + ] + )->getId(); + + // add deals to bitrix24 + $rawDeals = []; + for ($i = 0; $i < self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_PAGE_SIZE; $i++) { + $rawDeals[] = [ + 'TITLE' => sprintf('deal-%s', $i), + 'IS_MANUAL_OPPORTUNITY' => 'Y', + 'OPPORTUNITY' => sprintf('%s.00', random_int(100, 40000)), + 'CURRENCY_ID' => DemoDataGenerator::getCurrency()->getCode(), + 'CONTACT_ID' => $contactId, + ]; + } + $dealIdList = []; + foreach ($this->serviceBuilder->getCRMScope()->deal()->batch->add($rawDeals) as $addDealResult) { + $dealIdList[] = $addDealResult->getId(); + } + $this->assertCount(self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_PAGE_SIZE, $dealIdList); + + + // count added deals by default deal service + $filter = [ + 'CONTACT_ID' => $contactId, + ]; + + $elementsCountByFilter = $this->serviceBuilder->getCRMScope()->deal()->countByFilter($filter); + $this->assertEquals(self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_PAGE_SIZE, $elementsCountByFilter); + + $select = [ + '*', + ]; + + $dealIdListFromBatch = []; + $batchElementsCount = 0; + $this->stopwatch->start('getTraversableList'); + foreach ($this->batch->getTraversableList('crm.deal.list', [], $filter, $select) as $cnt => $dealItem) { + $batchElementsCount++; + $dealIdListFromBatch[] = $dealItem['ID']; + } + $this->stopwatch->stop('getTraversableList'); + $this->assertEquals( + self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_PAGE_SIZE, + $batchElementsCount, + sprintf( + 'elements count by filter %s not equals elements count from batch getTraversableList %s', + $elementsCountByFilter, + $batchElementsCount + ) + ); + $this->assertEquals($dealIdList, $dealIdListFromBatch, sprintf('added deal id array doesnt not equals array in batch result list')); + + print(sprintf( + 'getTraversableList timing - %s ms | %s sec' . PHP_EOL, + $this->stopwatch->getEvent('getTraversableList')->getDuration(), + $this->stopwatch->getEvent('getTraversableList')->getDuration() / 1000 + )); + + //try to delete deals + $deletedItemsCount = 0; + foreach ($this->batch->deleteEntityItems('crm.deal.delete', $dealIdList) as $cnt => $deletedResult) { + $deletedItemsCount++; + } + $this->assertEquals( + self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_PAGE_SIZE, + $deletedItemsCount, + sprintf( + 'elements count by filter %s not equals deleted elements count from batch deleteEntityItems %s', + $elementsCountByFilter, + $deletedItemsCount + ) + ); + } + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Exception + * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + * @covers \Bitrix24\SDK\Core\Batch::getTraversableList + * @testdox Get traversable list items in batch mode with less than one page with limit elements + */ + public function testGetTraversableListWithLessThanPageSizeWithLimit(): void + { + // prepare demo data + $contactId = $this->serviceBuilder->getCRMScope()->contact()->add( + [ + 'NAME' => sprintf('first_%s', time()), + 'SECOND' => sprintf('second_%s', time()), + ] + )->getId(); + + // add deals to bitrix24 + $rawDeals = []; + for ($i = 0; $i < self::DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE; $i++) { + $rawDeals[] = [ + 'TITLE' => sprintf('deal-%s', $i), + 'IS_MANUAL_OPPORTUNITY' => 'Y', + 'OPPORTUNITY' => sprintf('%s.00', random_int(100, 40000)), + 'CURRENCY_ID' => DemoDataGenerator::getCurrency()->getCode(), + 'CONTACT_ID' => $contactId, + ]; + } + $dealIdList = []; + foreach ($this->serviceBuilder->getCRMScope()->deal()->batch->add($rawDeals) as $addDealResult) { + $dealIdList[] = $addDealResult->getId(); + } + $this->assertCount(self::DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE, $dealIdList); + + + // count added deals by default deal service + $filter = [ + 'CONTACT_ID' => $contactId, + ]; + + $elementsCountByFilter = $this->serviceBuilder->getCRMScope()->deal()->countByFilter($filter); + $this->assertEquals(self::DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE, $elementsCountByFilter); + + $select = [ + 'ID', + 'TITLE', + 'OPPORTUNITY', + ]; + + $limitElements = self::LIMIT_ELEMENTS_IN_RESULT; + $batchElementsCount = 0; + $this->stopwatch->start('getTraversableList'); + foreach ($this->batch->getTraversableList('crm.deal.list', [], $filter, $select, $limitElements) as $cnt => $dealItem) { + $batchElementsCount++; + print(sprintf( + '%s-%s| %s | %s - %s', + $cnt, + $limitElements, + $dealItem['ID'], + $dealItem['TITLE'], + $dealItem['OPPORTUNITY'], + ) . PHP_EOL); + } + $this->stopwatch->stop('getTraversableList'); + $this->assertEquals( + $limitElements, + $batchElementsCount, + sprintf( + 'elements count by filter %s not equals elements count from batch getTraversableList %s', + $limitElements, + $batchElementsCount + ) + ); + } + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Exception + * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface + * @covers \Bitrix24\SDK\Core\Batch::getTraversableList + * @testdox Get traversable list items in batch mode with count more than one page without limit + */ + public function testGetTraversableListWithLessThanPageSizeWithoutLimit(): void + { + // prepare demo data + $contactId = $this->serviceBuilder->getCRMScope()->contact()->add( + [ + 'NAME' => sprintf('first_%s', time()), + 'SECOND' => sprintf('second_%s', time()), + ] + )->getId(); + + // add deals to bitrix24 + $rawDeals = []; + for ($i = 0; $i < self::DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE; $i++) { + $rawDeals[] = [ + 'TITLE' => sprintf('deal-%s', $i), + 'IS_MANUAL_OPPORTUNITY' => 'Y', + 'OPPORTUNITY' => sprintf('%s.00', random_int(100, 40000)), + 'CURRENCY_ID' => DemoDataGenerator::getCurrency()->getCode(), + 'CONTACT_ID' => $contactId, + ]; + } + $dealIdList = []; + foreach ($this->serviceBuilder->getCRMScope()->deal()->batch->add($rawDeals) as $addDealResult) { + $dealIdList[] = $addDealResult->getId(); + } + $this->assertCount(self::DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE, $dealIdList); + + + // count added deals by default deal service + $filter = [ + 'CONTACT_ID' => $contactId, + ]; + + $elementsCountByFilter = $this->serviceBuilder->getCRMScope()->deal()->countByFilter($filter); + $this->assertEquals(self::DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE, $elementsCountByFilter); + + $select = [ + 'ID', + 'TITLE', + 'OPPORTUNITY', + ]; + + $batchElementsCount = 0; + $this->stopwatch->start('getTraversableList'); + foreach ($this->batch->getTraversableList('crm.deal.list', [], $filter, $select) as $cnt => $dealItem) { + $batchElementsCount++; + print(sprintf( + '%s-%s| %s | %s - %s', + $cnt, + $elementsCountByFilter, + $dealItem['ID'], + $dealItem['TITLE'], + $dealItem['OPPORTUNITY'], + ) . PHP_EOL); + } + $this->stopwatch->stop('getTraversableList'); + $this->assertEquals( + $elementsCountByFilter, + $batchElementsCount, + sprintf( + 'elements count by filter %s not equals elements count from batch getTraversableList %s', + $elementsCountByFilter, + $batchElementsCount + ) + ); + } + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Exception + * @covers \Bitrix24\SDK\Core\Batch::addEntityItems + * @testdox Add items in batch mode + */ + public function testBatchAddEntityItems(): void + { + // prepare demo data + $contactId = $this->serviceBuilder->getCRMScope()->contact()->add( + [ + 'NAME' => sprintf('first_%s', time()), + 'SECOND' => sprintf('second_%s', time()), + ] + )->getId(); + $rawDeals = []; + for ($i = 0; $i < self::DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE; $i++) { + $rawDeals[] = [ + [ + 'fields' => [ + 'TITLE' => sprintf('deal-%s', $i), + 'OPPORTUNITY' => random_int(100, 40000), + 'CONTACT_ID' => $contactId, + ], + ], + ]; + } + + // add deals to bitrix24 + $dealIdList = []; + foreach ($this->batch->addEntityItems('crm.deal.add', $rawDeals) as $cnt => $addDealResult) { + $dealIdList[] = $addDealResult->getResult()[0]; + } + $this->assertCount(self::DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE, $dealIdList); + } + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Exception + * @covers \Bitrix24\SDK\Core\Batch::addEntityItems + * @covers \Bitrix24\SDK\Core\Batch::deleteEntityItems + * @testdox Delete items in batch mode + */ + public function testBatchDeleteEntityItems(): void + { + // prepare demo data + $contactId = $this->serviceBuilder->getCRMScope()->contact()->add( + [ + 'NAME' => sprintf('first_%s', time()), + 'SECOND' => sprintf('second_%s', time()), + ] + )->getId(); + $rawDeals = []; + for ($i = 0; $i < self::DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE; $i++) { + $rawDeals[] = [ + [ + 'fields' => [ + 'TITLE' => sprintf('deal-%s', $i), + 'OPPORTUNITY' => random_int(100, 40000), + 'CONTACT_ID' => $contactId, + ], + ], + ]; + } + + // add deals to bitrix24 + $dealIdList = []; + foreach ($this->batch->addEntityItems('crm.deal.add', $rawDeals) as $cnt => $addDealResult) { + $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()[0]; + } + $this->assertCount(self::DEMO_DATA_ARRAY_SIZE_LESS_THAN_PAGE, $dealsDeleteResult); + } + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @testdox Delete items in batch mode with wrong type of entity id + */ + 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()[0]; + } + } + + public function setUp(): void + { + $this->stopwatch = new Stopwatch(true); + $this->batch = Fabric::getBatchService(); + $this->serviceBuilder = Fabric::getServiceBuilder(); + } + + public function tearDown(): void + { + } +} \ No newline at end of file diff --git a/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrderTest.php b/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrderTest.php new file mode 100644 index 00000000..503c7b87 --- /dev/null +++ b/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrderTest.php @@ -0,0 +1,127 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Core\BulkItemsReader\ReadStrategies; + +use Bitrix24\SDK\Core\BulkItemsReader\ReadStrategies\FilterWithBatchWithoutCountOrder; +use Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface; +use Bitrix24\SDK\Services\ServiceBuilder; +use Bitrix24\SDK\Tests\Builders\DemoDataGenerator; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\TestCase; +use Symfony\Component\Stopwatch\Stopwatch; + +class FilterWithBatchWithoutCountOrderTest extends TestCase +{ + private BulkItemsReaderInterface $bulkItemsReader; + private ServiceBuilder $serviceBuilder; + private Stopwatch $stopwatch; + private int $contactId; + /** + * @var int[] + */ + private array $dealId; + private const DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_BATCH_PAGE_SIZE = 65; + /** + * @var array + */ + private array $filter; + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Exception + * @covers FilterWithBatchWithoutCountOrder::getTraversableList + * @testdox Get traversable list batch without count elements on every api call with elements count more than batch page size - 2500 elements + */ + public function testGetTraversableListBatchWithoutCountElementsOnEveryApiCallWithMoreThanBatchPageSizeFilterResult(): void + { + $elementsCountByFilter = $this->serviceBuilder->getCRMScope()->deal()->countByFilter($this->filter); + $this->assertEquals(self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_BATCH_PAGE_SIZE, $elementsCountByFilter); + + $select = [ + 'ID', + 'TITLE', + 'OPPORTUNITY', + ]; + + $elementsCount = 0; + $this->stopwatch->start('FilterWithBatchWithoutCountOrder.getTraversableList'); + foreach ($this->bulkItemsReader->getTraversableList('crm.deal.list', [], $this->filter, $select) as $cnt => $dealItem) { + $elementsCount++; + } + $this->stopwatch->stop('FilterWithBatchWithoutCountOrder.getTraversableList'); + $this->assertEquals( + $elementsCountByFilter, + $elementsCount, + sprintf( + 'elements count by filter %s not equals elements count from batch %s', + $elementsCountByFilter, + $elementsCount + ) + ); + + print(sprintf( + 'duration for FilterWithBatchWithoutCountOrder.getTraversableList: %s ms', + $this->stopwatch->getEvent('FilterWithBatchWithoutCountOrder.getTraversableList')->getDuration() + ) . PHP_EOL); + } + + public function setUp(): void + { + $this->stopwatch = new Stopwatch(true); + $this->serviceBuilder = Fabric::getServiceBuilder(); + $this->bulkItemsReader = new FilterWithBatchWithoutCountOrder( + Fabric::getBatchService(), + Fabric::getLogger() + ); + + // prepare demo data + // add contact + $this->contactId = $this->serviceBuilder->getCRMScope()->contact()->add( + [ + 'NAME' => sprintf('first_%s', time()), + 'SECOND' => sprintf('second_%s', time()), + ] + )->getId(); + + $this->filter = [ + 'CONTACT_ID' => $this->contactId, + ]; + + // add deals to bitrix24 + for ($i = 0; $i < self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_BATCH_PAGE_SIZE; $i++) { + $rawDeals[] = [ + 'TITLE' => sprintf('deal-%s', $i), + 'IS_MANUAL_OPPORTUNITY' => 'Y', + 'OPPORTUNITY' => sprintf('%s.00', random_int(100, 40000)), + 'CURRENCY_ID' => DemoDataGenerator::getCurrency()->getCode(), + 'CONTACT_ID' => $this->contactId, + ]; + } + foreach ($this->serviceBuilder->getCRMScope()->deal()->batch->add($rawDeals) as $addDealResult) { + $this->dealId[] = $addDealResult->getId(); + } + } + + public function tearDown(): void + { + // clear demo data + $this->serviceBuilder->getCRMScope()->contact()->delete($this->contactId); + $cnt = 0; + foreach ($this->serviceBuilder->getCRMScope()->deal()->batch->delete($this->dealId) as $cnt => $result) { + $cnt++; + } + } +} \ No newline at end of file diff --git a/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrderTest.php b/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrderTest.php new file mode 100644 index 00000000..7717e607 --- /dev/null +++ b/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrderTest.php @@ -0,0 +1,139 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Core\BulkItemsReader\ReadStrategies; + +use Bitrix24\SDK\Core\Batch; +use Bitrix24\SDK\Core\BulkItemsReader\ReadStrategies\FilterWithoutBatchWithoutCountOrder; +use Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface; +use Bitrix24\SDK\Services\ServiceBuilder; +use Bitrix24\SDK\Tests\Builders\DemoDataGenerator; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\TestCase; +use Symfony\Component\Stopwatch\Stopwatch; + +class FilterWithoutBatchWithoutCountOrderTest extends TestCase +{ + private const DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_BATCH_PAGE_SIZE = 65; + private BulkItemsReaderInterface $bulkItemsReader; + private ServiceBuilder $serviceBuilder; + private Stopwatch $stopwatch; + private int $contactId; + /** + * @var int[] + */ + private array $dealId; + /** + * @var array + */ + private array $filter; + + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Exception + * @covers \Bitrix24\SDK\Core\Batch::getTraversableList + * @testdox Get traversable list filter without batch without count ordered result + */ + public function testGetTraversableListFilterWithoutBatchWithoutCountOrder(): void + { + $elementsCountByFilter = $this->serviceBuilder->getCRMScope()->deal()->countByFilter($this->filter); + $this->assertEquals(self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_BATCH_PAGE_SIZE, $elementsCountByFilter); + + + $select = [ + 'ID', + 'TITLE', + 'OPPORTUNITY', + ]; + + $elementsCount = 0; + $this->stopwatch->start('FilterWithoutBatchWithoutCountOrder'); + foreach ( + $this->bulkItemsReader->getTraversableList( + 'crm.deal.list', + ['ID' => 'ASC'], + $this->filter, + $select + ) as $cnt => $dealItem + ) { + $elementsCount++; + } + $this->stopwatch->stop('FilterWithoutBatchWithoutCountOrder'); + $this->assertEquals( + $elementsCountByFilter, + $elementsCount, + sprintf( + 'elements count by filter %s not equals elements count from batch %s', + $elementsCountByFilter, + $elementsCount + ) + ); + + print(sprintf( + 'FilterWithoutBatchWithoutCountOrder: %s ms', + $this->stopwatch->getEvent('FilterWithoutBatchWithoutCountOrder')->getDuration() + ) . PHP_EOL); + + $this->assertTrue(true); + } + + public function setUp(): void + { + $this->stopwatch = new Stopwatch(true); + $this->serviceBuilder = Fabric::getServiceBuilder(); + $this->bulkItemsReader = new FilterWithoutBatchWithoutCountOrder( + Fabric::getCore(), + Fabric::getLogger() + ); + + // prepare demo data + // add contact + $this->contactId = $this->serviceBuilder->getCRMScope()->contact()->add( + [ + 'NAME' => sprintf('first_%s', time()), + 'SECOND' => sprintf('second_%s', time()), + ] + )->getId(); + + $this->filter = [ + 'CONTACT_ID' => $this->contactId, + ]; + + // add deals to bitrix24 + for ($i = 0; $i < self::DEMO_DATA_ARRAY_SIZE_MORE_THAN_ONE_BATCH_PAGE_SIZE; $i++) { + $rawDeals[] = [ + 'TITLE' => sprintf('deal-%s', $i), + 'IS_MANUAL_OPPORTUNITY' => 'Y', + 'OPPORTUNITY' => sprintf('%s.00', random_int(100, 40000)), + 'CURRENCY_ID' => DemoDataGenerator::getCurrency()->getCode(), + 'CONTACT_ID' => $this->contactId, + ]; + } + foreach ($this->serviceBuilder->getCRMScope()->deal()->batch->add($rawDeals) as $addDealResult) { + $this->dealId[] = $addDealResult->getId(); + } + } + + public function tearDown(): void + { + // clear demo data + $this->serviceBuilder->getCRMScope()->contact()->delete($this->contactId); + $cnt = 0; + foreach ($this->serviceBuilder->getCRMScope()->deal()->batch->delete($this->dealId) as $cnt => $result) { + $cnt++; + } + } +} \ No newline at end of file diff --git a/tests/Integration/Core/CoreTest.php b/tests/Integration/Core/CoreTest.php new file mode 100644 index 00000000..e972f3bc --- /dev/null +++ b/tests/Integration/Core/CoreTest.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Core; + +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\CoreBuilder; +use Bitrix24\SDK\Core\Credentials\AuthToken; +use Bitrix24\SDK\Core\Credentials\ApplicationProfile; +use Bitrix24\SDK\Core\Credentials\Credentials; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\MethodNotFoundException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; +use Symfony\Component\Stopwatch\Stopwatch; + +class CoreTest extends TestCase +{ + protected CoreInterface $core; + protected LoggerInterface $log; + protected Stopwatch $stopwatch; + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function testCallExistingApiMethod(): void + { + $response = $this->core->call('app.info'); + $this->assertIsArray($response->getResponseData()->getResult()); + } + + public function testConnectToNonExistsBitrix24PortalInCloud():void + { + $core = (new CoreBuilder()) + ->withLogger($this->log) + ->withCredentials(Credentials::createFromOAuth( + new AuthToken('non-exists-access-token','refresh-token', 3600), + new ApplicationProfile('non-exists-client-id', 'non-exists-client-secret', new Scope([])), + 'non-exists-domain.bitrix24.com' + )) + ->build(); + $this->expectException(TransportException::class); + $core->call('app.info'); + } + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + */ + public function testCallUnknownApiMethod(): void + { + $this->expectException(MethodNotFoundException::class); + $response = $this->core->call('unknownMethod'); + } + + public function setUp(): void + { + $this->core = Fabric::getCore(); + $this->stopwatch = new Stopwatch(true); + $this->log = Fabric::getLogger(); + } +} \ No newline at end of file diff --git a/tests/Integration/Fabric.php b/tests/Integration/Fabric.php new file mode 100644 index 00000000..238e4b9b --- /dev/null +++ b/tests/Integration/Fabric.php @@ -0,0 +1,140 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration; + +use Bitrix24\SDK\Core\Batch; +use Bitrix24\SDK\Core\BulkItemsReader\BulkItemsReaderBuilder; +use Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\CoreBuilder; +use Bitrix24\SDK\Core\Credentials\ApplicationProfile; +use Bitrix24\SDK\Core\Credentials\Credentials; +use Bitrix24\SDK\Core\Credentials\WebhookUrl; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Events\AuthTokenRenewedEvent; +use Bitrix24\SDK\Services\ServiceBuilder; +use Bitrix24\SDK\Tests\ApplicationBridge\ApplicationCredentialsProvider; +use Monolog\Handler\StreamHandler; +use Monolog\Logger; +use Monolog\Processor\IntrospectionProcessor; +use Monolog\Processor\MemoryUsageProcessor; +use Psr\Log\LoggerInterface; +use Symfony\Component\Dotenv\Dotenv; +use Symfony\Component\EventDispatcher\EventDispatcher; + +/** + * Class Fabric + * + * @package Bitrix24\SDK\Tests\Integration + */ +class Fabric +{ + /** + * @param bool $isNeedApplicationCredentials some rest-api methods need application credentials, incoming webhook doesn't work for call this methods + * @return ServiceBuilder + * @throws InvalidArgumentException + */ + public static function getServiceBuilder(bool $isNeedApplicationCredentials = false): ServiceBuilder + { + return new ServiceBuilder( + self::getCore($isNeedApplicationCredentials), + 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 + */ + public static function getBulkItemsReader(): BulkItemsReaderInterface + { + return (new BulkItemsReaderBuilder(self::getCore(), self::getBatchService(), self::getLogger()))->build(); + } + + /** + * @param bool $isNeedApplicationCredentials + * @return CoreInterface + * @throws InvalidArgumentException + */ + public static function getCore(bool $isNeedApplicationCredentials = false): CoreInterface + { + $default = (new CoreBuilder()) + ->withLogger(self::getLogger()) + ->withCredentials( + Credentials::createFromWebhook( + new WebhookUrl($_ENV['BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK'] ?? $_ENV['BITRIX24_WEBHOOK']) + ) + ) + ->build(); + + if ($isNeedApplicationCredentials) { + // load application credentials and rewrite default incoming webhook credentials from bootstrap.php file + (new Dotenv())->loadEnv(dirname(__DIR__, 2) . '/tests/ApplicationBridge/.env'); + + $credentialsProvider = ApplicationCredentialsProvider::buildProviderForLocalApplication(); + + if ($credentialsProvider->isCredentialsAvailable()) { + // register event handler for store new tokens + $eventDispatcher = new EventDispatcher(); + $eventDispatcher->addListener(AuthTokenRenewedEvent::class, [ + $credentialsProvider, + 'onAuthTokenRenewedEventListener' + ]); + + $credentials = $credentialsProvider->getCredentials( + ApplicationProfile::initFromArray($_ENV), + $_ENV['BITRIX24_PHP_SDK_APPLICATION_DOMAIN_URL']); + + return (new CoreBuilder()) + ->withLogger(self::getLogger()) + ->withEventDispatcher($eventDispatcher) + ->withCredentials($credentials) + ->build(); + } + } + return $default; + } + + /** + * @return \Psr\Log\LoggerInterface + */ + public static function getLogger(): LoggerInterface + { + $log = new Logger('integration-test'); + $log->pushHandler(new StreamHandler(STDOUT, (int)$_ENV['INTEGRATION_TEST_LOG_LEVEL'])); + $log->pushProcessor(new MemoryUsageProcessor(true, true)); + $log->pushProcessor(new IntrospectionProcessor()); + + return $log; + } + + /** + * @return \Bitrix24\SDK\Core\Batch + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public static function getBatchService(): Batch + { + return new Batch(self::getCore(), self::getLogger()); + } +} \ No newline at end of file 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..b9855548 --- /dev/null +++ b/tests/Integration/Services/CRM/Activity/ReadModel/EmailFetcherTest.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Activity\ReadModel; + +use Bitrix24\SDK\Services\CRM\Activity\ReadModel\EmailFetcher; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\TestCase; + +class EmailFetcherTest extends TestCase +{ + private EmailFetcher $emailFetcher; + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @covers \Bitrix24\SDK\Services\CRM\Activity\ReadModel\WebFormFetcher::getList + */ + public function testGetListWithAllResults(): void + { + // we can't guarantee open lines data on test env + $itemsCnt = 0; + foreach ($this->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..c4ad949f --- /dev/null +++ b/tests/Integration/Services/CRM/Activity/ReadModel/OpenLineFetcherTest.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Activity\ReadModel; + +use Bitrix24\SDK\Services\CRM\Activity\ReadModel\OpenLineFetcher; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\TestCase; + +class OpenLineFetcherTest extends TestCase +{ + private OpenLineFetcher $openLineFetcher; + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @covers \Bitrix24\SDK\Services\CRM\Activity\ReadModel\WebFormFetcher::getList + */ + public function testGetListWithAllResults(): void + { + // we can't guarantee open lines data on test env + $itemsCnt = 0; + foreach ($this->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..273739f3 --- /dev/null +++ b/tests/Integration/Services/CRM/Activity/ReadModel/VoximplantFetcherTest.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Activity\ReadModel; + +use Bitrix24\SDK\Services\CRM\Activity\ReadModel\VoximplantFetcher; +use Bitrix24\SDK\Services\CRM\Activity\ReadModel\WebFormFetcher; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\TestCase; + +class VoximplantFetcherTest extends TestCase +{ + private VoximplantFetcher $voximplantFetcher; + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @covers \Bitrix24\SDK\Services\CRM\Activity\ReadModel\WebFormFetcher::getList + */ + public function testGetListWithAllResults(): void + { + // we can't guarantee calls data on test env + $itemsCnt = 0; + foreach ($this->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..92bc50e7 --- /dev/null +++ b/tests/Integration/Services/CRM/Activity/ReadModel/WebFormFetcherTest.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Activity\ReadModel; + +use Bitrix24\SDK\Services\CRM\Activity\ReadModel\WebFormFetcher; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\TestCase; + +class WebFormFetcherTest extends TestCase +{ + private WebFormFetcher $webFormFetcher; + + /** + * @return void + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @covers \Bitrix24\SDK\Services\CRM\Activity\ReadModel\WebFormFetcher::getList + */ + public function testGetListWithAllWebFormResults(): void + { + // we can't guarantee filled web-form on test env + $itemsCnt = 0; + foreach ($this->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..758717ed --- /dev/null +++ b/tests/Integration/Services/CRM/Activity/Service/ActivityTest.php @@ -0,0 +1,283 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Activity\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\CRM\Activity\ActivityContentType; +use Bitrix24\SDK\Services\CRM\Activity\ActivityDirectionType; +use Bitrix24\SDK\Services\CRM\Activity\Result\ActivityItemResult; +use Bitrix24\SDK\Services\CRM\Activity\Service\Activity; +use Bitrix24\SDK\Services\CRM\Activity\ActivityType; +use Bitrix24\SDK\Services\CRM\Contact\Service\Contact; +use Bitrix24\SDK\Services\CRM\Deal\Result\DealProductRowItemResult; +use Bitrix24\SDK\Tests\Builders\DemoDataGenerator; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\TestCase; +use Typhoon\Reflection\TyphoonReflector; + +class ActivityTest extends TestCase +{ + private Activity $activityService; + private Contact $contactService; + private array $contactId; + private array $activityId; + + /** + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Activity\Service\Activity::add + */ + public function testAdd(): void + { + $contactId = $this->contactService->add(['NAME' => 'test contact'])->getId(); + $this->contactId[] = $contactId; + $this->activityId[] = $this->activityService->add( + [ + 'OWNER_ID' => $contactId, + 'OWNER_TYPE_ID' => 3, + 'TYPE_ID' => ActivityType::call->value, + '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' => DemoDataGenerator::getMobilePhone()->getNationalNumber(), + ], + ], + ] + )->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' => ActivityType::call->value, + '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' => DemoDataGenerator::getMobilePhone()->getNationalNumber(), + ], + ], + ] + )->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' => ActivityType::call->value, + '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' => DemoDataGenerator::getMobilePhone()->getNationalNumber(), + ], + ], + ]; + $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' => ActivityType::call->value, + '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' => DemoDataGenerator::getMobilePhone()->getNationalNumber(), + ], + ], + ]; + $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' => ActivityType::call->value, + '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' => DemoDataGenerator::getMobilePhone()->getNationalNumber(), + ], + ], + ]; + $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' => ActivityType::call->value, + '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' => DemoDataGenerator::getMobilePhone()->getNationalNumber(), + ], + ], + ]; + $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..f2d32bd1 --- /dev/null +++ b/tests/Integration/Services/CRM/Activity/Service/BatchTest.php @@ -0,0 +1,199 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Activity\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\CRM\Activity\Service\Activity; +use Bitrix24\SDK\Services\CRM\Contact\Service\Contact; +use Bitrix24\SDK\Tests\Builders\DemoDataGenerator; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\TestCase; + +class BatchTest extends TestCase +{ + private Contact $contactService; + private Activity $activityService; + private const BATCH_TEST_ELEMENTS_COUNT = 60; + private array $contactId; + + /** + * @testdox Batch add deals + * @covers \Bitrix24\SDK\Services\CRM\Activity\Service\Batch::add() + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function testBatchAdd(): 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' => DemoDataGenerator::getMobilePhone()->getNationalNumber(), + ], + ], + ]; + } + + $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' => DemoDataGenerator::getMobilePhone()->getNationalNumber(), + ], + ], + ]; + } + + $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' => DemoDataGenerator::getMobilePhone()->getNationalNumber(), + ], + ], + ]; + } + + $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/Contact/Service/ContactBatchTest.php b/tests/Integration/Services/CRM/Contact/Service/ContactBatchTest.php new file mode 100644 index 00000000..af252f53 --- /dev/null +++ b/tests/Integration/Services/CRM/Contact/Service/ContactBatchTest.php @@ -0,0 +1,131 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Contact\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\CRM\Contact\Service\Contact; +use Bitrix24\SDK\Tests\Builders\Services\CRM\PhoneCollectionBuilder; +use Bitrix24\SDK\Tests\Builders\Services\CRM\PhoneNumberBuilder; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\TestCase; + +/** + * Class ContactTest + * + * @package Bitrix24\SDK\Tests\Integration\Services\CRM\Contact\Service + */ +class ContactBatchTest extends TestCase +{ + private const TEST_SEGMENT_ELEMENTS_COUNT = 400; + + protected Contact $contactService; + + /** + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Contact\Service\Batch::list() + */ + public function testBatchList(): void + { + $this->contactService->add(['NAME' => 'test contact']); + $cnt = 0; + + foreach ($this->contactService->batch->list([], ['>ID' => '1'], ['ID', 'NAME'], 1) as $item) { + $cnt++; + } + self::assertGreaterThanOrEqual(1, $cnt); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Contact\Service\Batch::add() + */ + public function testBatchAdd(): void + { + $contacts = []; + for ($i = 1; $i < 60; $i++) { + $contacts[] = ['NAME' => 'name-' . $i]; + } + $cnt = 0; + foreach ($this->contactService->batch->add($contacts) as $item) { + $cnt++; + } + + self::assertEquals(count($contacts), $cnt); + } + + /** + * @return void + * @throws BaseException + * @covers \Bitrix24\SDK\Services\CRM\Contact\Service\Batch::update() + */ + public function testBatchUpdate(): void + { + // add contacts + $contacts = []; + for ($i = 1; $i <= self::TEST_SEGMENT_ELEMENTS_COUNT; $i++) { + $contacts[] = [ + 'NAME' => 'name-' . time(), + 'SECOND_NAME' => 'second_name-' . time(), + 'LAST_NAME' => 'last_name-' . time(), + 'PHONE' => [ + [ + 'VALUE' => (new PhoneNumberBuilder())->build(), + 'VALUE_TYPE' => 'WORK' + ] + ] + ]; + } + $cnt = 0; + $contactId = []; + foreach ($this->contactService->batch->add($contacts) as $item) { + $cnt++; + $contactId[] = $item->getId(); + } + self::assertEquals(count($contacts), $cnt); + + // generate update data + $updateContactData = []; + foreach ($contactId as $id) { + $updateContactData[$id] = [ + 'fields' => [ + 'NAME' => 'name-' . $id . '-updated' + ], + ]; + } + + // update contacts in batch mode + $cnt = 0; + foreach ($this->contactService->batch->update($updateContactData) as $item) { + $cnt++; + $this->assertTrue($item->isSuccess()); + } + self::assertEquals(count($contacts), $cnt); + + // delete contacts + $cnt = 0; + foreach ($this->contactService->batch->delete($contactId) as $item) { + $cnt++; + $this->assertTrue($item->isSuccess()); + } + self::assertEquals(count($contacts), $cnt); + } + + public function setUp(): void + { + $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); + } +} diff --git a/tests/Integration/Services/CRM/Contact/Service/ContactTest.php b/tests/Integration/Services/CRM/Contact/Service/ContactTest.php new file mode 100644 index 00000000..425fe881 --- /dev/null +++ b/tests/Integration/Services/CRM/Contact/Service/ContactTest.php @@ -0,0 +1,236 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Contact\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\EmailValueType; +use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\InstantMessengerValueType; +use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\PhoneValueType; +use Bitrix24\SDK\Services\CRM\Common\Result\SystemFields\Types\WebsiteValueType; +use Bitrix24\SDK\Services\CRM\Contact\Result\ContactItemResult; +use Bitrix24\SDK\Services\CRM\Contact\Service\Contact; +use Bitrix24\SDK\Tests\CustomAssertions\CustomBitrix24Assertions; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\TestCase; +use Bitrix24\SDK\Core; +use Faker; + +/** + * Class ContactTest + * + * @package Bitrix24\SDK\Tests\Integration\Services\CRM\Contact\Service + */ +class ContactTest extends TestCase +{ + use CustomBitrix24Assertions; + + private Contact $contactService; + private Faker\Generator $faker; + + /** + * @throws BaseException + * @throws TransportException + * @covers Contact::add + */ + public function testAdd(): void + { + self::assertGreaterThanOrEqual(1, $this->contactService->add(['NAME' => 'test contact'])->getId()); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers Contact::delete + */ + public function testDelete(): void + { + self::assertTrue($this->contactService->delete($this->contactService->add(['NAME' => 'test contact'])->getId())->isSuccess()); + } + + /** + * @covers Contact::fields + * @throws BaseException + * @throws TransportException + */ + public function testFields(): void + { + self::assertIsArray($this->contactService->fields()->getFieldsDescription()); + } + + public function testAllSystemFieldsAnnotated(): void + { + $propListFromApi = (new Core\Fields\FieldsFilter())->filterSystemFields(array_keys($this->contactService->fields()->getFieldsDescription())); + $this->assertBitrix24AllResultItemFieldsAnnotated($propListFromApi, ContactItemResult::class); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers Contact::get + */ + public function testGet(): void + { + self::assertGreaterThan( + 1, + $this->contactService->get($this->contactService->add(['NAME' => 'test contact'])->getId())->contact()->ID + ); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers Contact::list + */ + public function testList(): void + { + $this->contactService->add(['NAME' => 'test contact']); + self::assertGreaterThanOrEqual(1, $this->contactService->list([''], [''], ['ID', 'NAME'], 0)->getContacts()); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers Contact::update + */ + public function testUpdate(): void + { + $contact = $this->contactService->add(['NAME' => 'test']); + $newName = 'test2'; + + self::assertTrue($this->contactService->update($contact->getId(), ['NAME' => $newName], [])->isSuccess()); + self::assertEquals($newName, $this->contactService->get($contact->getId())->contact()->NAME); + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function testCountByFilter(): void + { + $totalBefore = $this->contactService->countByFilter(); + + $newContactsCount = 70; + + $contacts = []; + for ($i = 1; $i <= $newContactsCount; $i++) { + $contacts[] = ['NAME' => 'name-' . $i]; + } + + foreach ($this->contactService->batch->add($contacts) as $item) { + } + + $totalAfter = $this->contactService->countByFilter(); + + $this->assertEquals($totalBefore + $newContactsCount, $totalAfter); + } + + /** + * @return void + * @covers Contact::get + * @covers Contact::add + * @throws Core\Exceptions\TransportException + * @throws Core\Exceptions\BaseException + */ + public function testGetEmail(): void + { + $email = $this->faker->email(); + $this->assertEquals($email, + $this->contactService->get( + $this->contactService->add([ + 'NAME' => $this->faker->name(), + 'EMAIL' => [ + [ + 'VALUE' => $email, + 'VALUE_TYPE' => EmailValueType::work->name, + ] + ], + ])->getId())->contact()->EMAIL[0]->VALUE); + } + + /** + * @return void + * @covers Contact::get + * @covers Contact::add + * @throws Core\Exceptions\TransportException + * @throws Core\Exceptions\BaseException + */ + public function testGetPhone(): void + { + $phone = $this->faker->e164PhoneNumber(); + $this->assertEquals($phone, + $this->contactService->get( + $this->contactService->add([ + 'NAME' => $this->faker->name(), + 'PHONE' => [ + [ + 'VALUE' => $phone, + 'VALUE_TYPE' => PhoneValueType::work->name, + ] + ], + ])->getId())->contact()->PHONE[0]->VALUE); + } + + /** + * @return void + * @covers Contact::get + * @covers Contact::add + * @throws Core\Exceptions\TransportException + * @throws Core\Exceptions\BaseException + */ + public function testGetInstantMessenger(): void + { + $phone = $this->faker->e164PhoneNumber(); + $this->assertEquals($phone, + $this->contactService->get( + $this->contactService->add([ + 'NAME' => $this->faker->name(), + 'IM' => [ + [ + 'VALUE' => $phone, + 'VALUE_TYPE' => InstantMessengerValueType::telegram->name, + ] + ], + ])->getId())->contact()->IM[0]->VALUE); + } + + /** + * @return void + * @covers Contact::get + * @covers Contact::add + * @throws Core\Exceptions\TransportException + * @throws Core\Exceptions\BaseException + */ + public function testGetWebsite(): void + { + $url = $this->faker->url(); + $this->assertEquals($url, + $this->contactService->get( + $this->contactService->add([ + 'NAME' => $this->faker->name(), + 'WEB' => [ + [ + 'VALUE' => $url, + 'VALUE_TYPE' => WebsiteValueType::work->name, + ] + ], + ])->getId())->contact()->WEB[0]->VALUE); + } + + public function setUp(): void + { + $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); + $this->faker = Faker\Factory::create(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Contact/Service/ContactUserfieldTest.php b/tests/Integration/Services/CRM/Contact/Service/ContactUserfieldTest.php new file mode 100644 index 00000000..13204f6c --- /dev/null +++ b/tests/Integration/Services/CRM/Contact/Service/ContactUserfieldTest.php @@ -0,0 +1,151 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Contact\Service; + +use Bitrix24\SDK\Services\CRM\Contact\Service\ContactUserfield; +use Bitrix24\SDK\Tests\Integration\Fabric; +use Generator; +use PHPUnit\Framework\TestCase; + +class ContactUserfieldTest extends TestCase +{ + protected ContactUserfield $contactUserfieldService; + + /** + * @throws \Exception + */ + public function systemUserfieldsDemoDataDataProvider(): Generator + { + yield 'user type id string' => [ + [ + 'FIELD_NAME' => sprintf('%s%s', substr((string)random_int(0, PHP_INT_MAX), 0, 3), time()), + 'EDIT_FORM_LABEL' => [ + 'ru' => 'тест uf тип string', + 'en' => 'test uf type string', + ], + 'LIST_COLUMN_LABEL' => [ + 'ru' => 'тест uf тип string', + 'en' => 'test uf type string', + ], + 'USER_TYPE_ID' => 'string', + 'XML_ID' => 'b24phpsdk_type_string', + 'SETTINGS' => [], + ], + ]; + + mt_srand(); + yield 'user type id integer' => [ + [ + 'FIELD_NAME' => sprintf('%s%s', substr((string)random_int(0, PHP_INT_MAX), 0, 3), time()), + 'EDIT_FORM_LABEL' => [ + 'ru' => 'тест uf тип integer', + 'en' => 'test uf type integer', + ], + 'LIST_COLUMN_LABEL' => [ + 'ru' => 'тест uf тип integer', + 'en' => 'test uf type integer', + ], + 'USER_TYPE_ID' => 'integer', + 'XML_ID' => 'b24phpsdk_type_integer', + 'SETTINGS' => [], + ], + ]; + } + + /** + * @param array $newUserFieldItem + * + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNameIsTooLongException + * @covers ContactUserfield::add + * @dataProvider systemUserfieldsDemoDataDataProvider + */ + public function testAdd(array $newUserFieldItem): void + { + self::assertGreaterThanOrEqual(1, $this->contactUserfieldService->add($newUserFieldItem)->getId()); + } + + /** + * @param array $newUserFieldItem + * + * @dataProvider systemUserfieldsDemoDataDataProvider + * @covers ContactUserfield::delete + */ + public function testDelete(array $newUserFieldItem): void + { + $newUserfieldId = $this->contactUserfieldService->add($newUserFieldItem)->getId(); + $this->assertTrue($this->contactUserfieldService->delete($newUserfieldId)->isSuccess()); + } + + /** + * @param array $newUserFieldItem + * + * @dataProvider systemUserfieldsDemoDataDataProvider + * @covers ContactUserfield::get + */ + public function testGet(array $newUserFieldItem): void + { + $newUserfieldId = $this->contactUserfieldService->add($newUserFieldItem)->getId(); + $ufField = $this->contactUserfieldService->get($newUserfieldId)->userfieldItem(); + $this->assertEquals($newUserfieldId, $ufField->ID); + $this->assertEquals($newUserFieldItem['USER_TYPE_ID'], $ufField->USER_TYPE_ID); + $this->assertEquals('UF_CRM_' . $newUserFieldItem['FIELD_NAME'], $ufField->FIELD_NAME); + $this->assertEquals($newUserFieldItem['XML_ID'], $ufField->XML_ID); + } + + /** + * @param array $newUserFieldItem + * + * @dataProvider systemUserfieldsDemoDataDataProvider + * @covers ContactUserfield::update + */ + public function testUpdate(array $newUserFieldItem): void + { + $newUserfieldId = $this->contactUserfieldService->add($newUserFieldItem)->getId(); + $ufFieldBefore = $this->contactUserfieldService->get($newUserfieldId)->userfieldItem(); + $this->assertEquals($newUserfieldId, $ufFieldBefore->ID); + $this->assertEquals($newUserFieldItem['USER_TYPE_ID'], $ufFieldBefore->USER_TYPE_ID); + $this->assertEquals('UF_CRM_' . $newUserFieldItem['FIELD_NAME'], $ufFieldBefore->FIELD_NAME); + $this->assertEquals($newUserFieldItem['XML_ID'], $ufFieldBefore->XML_ID); + + $this->assertTrue( + $this->contactUserfieldService->update( + $newUserfieldId, + [ + 'EDIT_FORM_LABEL' => $newUserFieldItem['EDIT_FORM_LABEL']['en'] . 'QQQ', + ] + )->isSuccess() + ); + + $ufFieldAfter = $this->contactUserfieldService->get($newUserfieldId)->userfieldItem(); + $this->assertEquals($ufFieldBefore->EDIT_FORM_LABEL['en'] . 'QQQ', $ufFieldAfter->EDIT_FORM_LABEL['en']); + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @covers \Bitrix24\SDK\Services\CRM\Contact\Service\ContactUserfield::list + */ + public function testList(): void + { + $ufFields = $this->contactUserfieldService->list([], []); + $this->assertGreaterThanOrEqual(0, count($ufFields->getUserfields())); + } + + public function setUp(): void + { + $this->contactUserfieldService = Fabric::getServiceBuilder()->getCRMScope()->contactUserfield(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Contact/Service/ContactUserfieldUseCaseTest.php b/tests/Integration/Services/CRM/Contact/Service/ContactUserfieldUseCaseTest.php new file mode 100644 index 00000000..e61f7ae3 --- /dev/null +++ b/tests/Integration/Services/CRM/Contact/Service/ContactUserfieldUseCaseTest.php @@ -0,0 +1,101 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Contact\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\Contact\Service\ContactUserfield; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\TestCase; + +class ContactUserfieldUseCaseTest extends TestCase +{ + protected Contact $contactService; + protected ContactUserfield $contactUserfieldService; + protected int $contactUserfieldId; + + /** + * @throws BaseException + * @throws TransportException + * @covers Contact::add + */ + public function testOperationsWithUserfieldFromContactItem(): void + { + // get userfield metadata + $ufMetadata = $this->contactUserfieldService->get($this->contactUserfieldId)->userfieldItem(); + $ufOriginalFieldName = $ufMetadata->getOriginalFieldName(); + $ufFieldName = $ufMetadata->FIELD_NAME; + + // add contact with uf value + $fieldNameValue = 'test field value'; + $newContactId = $this->contactService->add( + [ + 'NAME' => 'test contact', + $ufFieldName => $fieldNameValue, + ] + )->getId(); + $contact = $this->contactService->get($newContactId)->contact(); + $this->assertEquals($fieldNameValue, $contact->getUserfieldByFieldName($ufOriginalFieldName)); + + // update contact userfield value + $newUfValue = 'test 2'; + $this->assertTrue( + $this->contactService->update( + $contact->ID, + [ + $ufFieldName => $newUfValue, + ] + )->isSuccess() + ); + $updatedContact = $this->contactService->get($contact->ID)->contact(); + $this->assertEquals($newUfValue, $updatedContact->getUserfieldByFieldName($ufOriginalFieldName)); + } + + /** + * @throws \Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNameIsTooLongException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function setUp(): void + { + $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); + $this->contactUserfieldService = Fabric::getServiceBuilder()->getCRMScope()->contactUserfield(); + + $this->contactUserfieldId = $this->contactUserfieldService->add( + [ + 'FIELD_NAME' => sprintf('%s%s', substr((string)random_int(0, PHP_INT_MAX), 0, 3), time()), + 'EDIT_FORM_LABEL' => [ + 'ru' => 'тест uf тип string', + 'en' => 'test uf type string', + ], + 'LIST_COLUMN_LABEL' => [ + 'ru' => 'тест uf тип string', + 'en' => 'test uf type string', + ], + 'USER_TYPE_ID' => 'string', + 'XML_ID' => 'b24phpsdk_type_string', + 'SETTINGS' => [ + 'DEFAULT_VALUE' => 'hello world', + ], + ] + )->getId(); + } + + public function tearDown(): void + { + $this->contactUserfieldService->delete($this->contactUserfieldId); + } +} \ 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 new file mode 100644 index 00000000..83aba611 --- /dev/null +++ b/tests/Integration/Services/CRM/Deal/Service/BatchTest.php @@ -0,0 +1,155 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Deal\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\CRM\Deal\Service\Deal; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\TestCase; + +/** + * Class DealsTest + * + * @package Bitrix24\SDK\Tests\Integration\Services\CRM\Deals\Service + */ +class BatchTest extends TestCase +{ + protected Deal $dealService; + + /** + * @testdox Batch list deals + * @covers \Bitrix24\SDK\Services\CRM\Contact\Service\Batch::list() + * @throws BaseException + * @throws TransportException + */ + public function testBatchList(): void + { + $dealId = $this->dealService->add(['TITLE' => 'test deal'])->getId(); + $cnt = 0; + + foreach ($this->dealService->batch->list([], ['ID' => $dealId], ['ID', 'NAME'], 1) as $item) { + $cnt++; + } + self::assertGreaterThanOrEqual(1, $cnt); + + $this->dealService->delete($dealId); + } + + /** + * @testdox Batch add deals + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\Batch::add() + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function testBatchAdd(): void + { + $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); + + $cnt = 0; + foreach ($this->dealService->batch->delete($dealId) as $cnt => $deleteResult) { + $cnt++; + } + self::assertEquals(count($deals), $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->dealService->batch->add($deals) as $item) { + $cnt++; + $dealId[] = $item->getId(); + } + self::assertEquals(count($deals), $cnt); + + $cnt = 0; + foreach ($this->dealService->batch->delete($dealId) as $cnt => $deleteResult) { + $cnt++; + } + 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(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Deal/Service/DealCategoryStageTest.php b/tests/Integration/Services/CRM/Deal/Service/DealCategoryStageTest.php new file mode 100644 index 00000000..cbe5aa81 --- /dev/null +++ b/tests/Integration/Services/CRM/Deal/Service/DealCategoryStageTest.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Deal\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\CRM\Deal\Service\DealCategory; +use Bitrix24\SDK\Services\CRM\Deal\Service\DealCategoryStage; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\TestCase; + +/** + * Class DealCategoryStageTest + * + * @package Bitrix24\SDK\Tests\Integration\Services\CRM\Deal\Service + */ +class DealCategoryStageTest extends TestCase +{ + protected DealCategoryStage $dealCategoryStage; + protected DealCategory $dealCategory; + + /** + * @covers DealCategoryStage::list() + * @throws BaseException + * @throws TransportException + */ + public function testList(): void + { + $newCategoryId = (int)$this->dealCategory->add(['NAME' => 'php unit test'])->getId(); + $res = $this->dealCategoryStage->list($newCategoryId); + $this::assertGreaterThan(1, count($res->getDealCategoryStages())); + } + + /** + * @throws InvalidArgumentException + */ + public function setUp(): void + { + $this->dealCategoryStage = Fabric::getServiceBuilder()->getCRMScope()->dealCategoryStage(); + $this->dealCategory = Fabric::getServiceBuilder()->getCRMScope()->dealCategory(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Deal/Service/DealCategoryTest.php b/tests/Integration/Services/CRM/Deal/Service/DealCategoryTest.php new file mode 100644 index 00000000..1e5aea71 --- /dev/null +++ b/tests/Integration/Services/CRM/Deal/Service/DealCategoryTest.php @@ -0,0 +1,172 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Deal\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\CRM\Deal\Service\DealCategory; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\TestCase; + +/** + * Class DealCategoryTest + * + * @package Bitrix24\SDK\Tests\Integration\Services\CRM\Deals\Service + */ +class DealCategoryTest extends TestCase +{ + protected DealCategory $dealCategory; + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealCategory::add + * + * @throws BaseException + * @throws TransportException + */ + public function testAdd(): void + { + $countBefore = $this->dealCategory->list([], [], [], 0)->getCoreResponse()->getResponseData()->getPagination()->getTotal(); + $this::assertGreaterThanOrEqual( + 1, + $this->dealCategory->add( + [ + 'NAME' => 'test', + 'SORT' => 20, + ] + )->getId() + ); + $countAfter = $this->dealCategory->list([], [], [], 0)->getCoreResponse()->getResponseData()->getPagination()->getTotal(); + + $this::assertEquals($countBefore + 1, $countAfter); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealCategory::delete + * @throws BaseException + * @throws TransportException + */ + public function testDelete(): void + { + $this::assertTrue( + $this->dealCategory->delete( + $this->dealCategory->add( + [ + 'NAME' => 'test_name', + ] + )->getId() + )->isSuccess() + ); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealCategory::fields + * @throws BaseException + * @throws TransportException + */ + public function testFields(): void + { + $this::assertIsArray($this->dealCategory->fields()->getFieldsDescription()); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealCategory::getDefaultCategorySettings + * @throws BaseException + * @throws TransportException + */ + public function testDealCategoryDefaultGet(): void + { + $this::assertGreaterThanOrEqual(0, $this->dealCategory->getDefaultCategorySettings()->getDealCategoryFields()->ID); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealCategory::setDefaultCategorySettings + * @throws BaseException + * @throws TransportException + */ + public function testDealCategoryDefaultSet(): void + { + $oldName = $this->dealCategory->getDefaultCategorySettings()->getDealCategoryFields()->NAME; + $newName = (string)time(); + $this::assertTrue($this->dealCategory->setDefaultCategorySettings(['NAME' => $newName])->isSuccess()); + $this::assertNotSame($oldName, $this->dealCategory->getDefaultCategorySettings()->getDealCategoryFields()->NAME); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealCategory::get + * @throws BaseException + * @throws TransportException + */ + public function testDealCategoryGet(): void + { + $newCategory = [ + 'NAME' => 'test new deal category', + 'SORT' => 300, + ]; + + $newCategoryId = $this->dealCategory->add($newCategory)->getId(); + $category = $this->dealCategory->get($newCategoryId); + + $this::assertEquals($newCategory['NAME'], $category->getDealCategoryFields()->NAME); + $this::assertEquals($newCategory['SORT'], $category->getDealCategoryFields()->SORT); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealCategory::list + * + * @throws BaseException + * @throws TransportException + */ + public function testList(): void + { + $res = $this->dealCategory->list([], [], [], 0); + $this::assertGreaterThanOrEqual(1, count($res->getDealCategories())); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealCategory::getStatus + * @throws BaseException + * @throws TransportException + */ + public function testDealCategoryStatus(): void + { + $newCategory = [ + 'NAME' => 'test new deal category', + 'SORT' => 300, + ]; + $newCategoryId = $this->dealCategory->add($newCategory)->getId(); + $status = $this->dealCategory->getStatus($newCategoryId); + $this::assertGreaterThan(1, strlen($status->getDealCategoryTypeId())); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealCategory::update + * @throws BaseException + * @throws TransportException + */ + public function testUpdate(): void + { + $newCategory = [ + 'NAME' => 'test new deal category', + 'SORT' => 300, + ]; + $newCategoryId = $this->dealCategory->add($newCategory)->getId(); + $this::assertTrue($this->dealCategory->update($newCategoryId, ['NAME' => 'updated'])->isSuccess()); + $this::assertEquals('updated', $this->dealCategory->get($newCategoryId)->getDealCategoryFields()->NAME); + } + + public function setUp(): void + { + $this->dealCategory = Fabric::getServiceBuilder()->getCRMScope()->dealCategory(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Deal/Service/DealContactTest.php b/tests/Integration/Services/CRM/Deal/Service/DealContactTest.php new file mode 100644 index 00000000..3c6da9a7 --- /dev/null +++ b/tests/Integration/Services/CRM/Deal/Service/DealContactTest.php @@ -0,0 +1,198 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Deal\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\Deal\Service\Deal; +use Bitrix24\SDK\Services\CRM\Deal\Service\DealContact; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\TestCase; + +/** + * Class DealsTest + * + * @package Bitrix24\SDK\Tests\Integration\Services\CRM\Deals\Service + */ +class DealContactTest extends TestCase +{ + protected Deal $dealService; + protected Contact $contactService; + private DealContact $dealContactService; + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealContact::add + * @throws BaseException + * @throws TransportException + */ + public function testAddWithPrimary(): void + { + $dealId = $this->dealService->add(['TITLE' => 'test deal'])->getId(); + $this::assertGreaterThanOrEqual( + 1, + $this->dealContactService->add( + $dealId, + $this->contactService->add(['NAME' => 'test contact'], [])->getId(), + true + )->getId() + ); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealContact::add + * @throws BaseException + * @throws TransportException + */ + public function testAddWithSecondary(): void + { + $dealId = $this->dealService->add(['TITLE' => 'test deal'])->getId(); + + $this::assertGreaterThanOrEqual( + 1, + $this->dealContactService->add($dealId, $this->contactService->add(['NAME' => 'test contact 1'], [])->getId(), true)->getId() + ); + $this::assertGreaterThanOrEqual( + 1, + $this->dealContactService->add($dealId, $this->contactService->add(['NAME' => 'test contact 2'], [])->getId(), false)->getId() + ); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealContact::itemsGet + * @throws BaseException + * @throws TransportException + */ + public function testItemsGet(): void + { + $dealId = $this->dealService->add(['TITLE' => 'test deal'])->getId(); + $this::assertGreaterThanOrEqual( + 1, + $this->dealContactService->add( + $dealId, + $this->contactService->add(['NAME' => 'test contact 1'], [])->getId(), + true + )->getId() + ); + $this::assertGreaterThanOrEqual( + 1, + $this->dealContactService->add( + $dealId, + $this->contactService->add(['NAME' => 'test contact 2'], [])->getId(), + false + )->getId() + ); + + $this::assertCount(2, $this->dealContactService->itemsGet($dealId)->getDealContacts()); + } + + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealContact::itemsDelete + * @throws BaseException + * @throws TransportException + */ + public function testItemsDelete(): void + { + $dealId = $this->dealService->add(['TITLE' => 'test deal'])->getId(); + $this::assertGreaterThanOrEqual( + 1, + $this->dealContactService->add( + $dealId, + $this->contactService->add(['NAME' => 'test contact 1'], [])->getId(), + true + )->getId() + ); + $this::assertGreaterThanOrEqual( + 1, + $this->dealContactService->add( + $dealId, + $this->contactService->add(['NAME' => 'test contact 2'], [])->getId(), + false + )->getId() + ); + $this::assertCount(2, $this->dealContactService->itemsGet($dealId)->getDealContacts()); + $this::assertTrue($this->dealContactService->itemsDelete($dealId)->isSuccess()); + $this::assertCount(0, $this->dealContactService->itemsGet($dealId)->getDealContacts()); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealContact::itemsSet + * @throws BaseException + * @throws TransportException + */ + public function testItemsSet(): void + { + $dealId = $this->dealService->add(['TITLE' => 'test deal'])->getId(); + $contact1Id = $this->contactService->add(['NAME' => 'test contact 1'], [])->getId(); + $contact2Id = $this->contactService->add(['NAME' => 'test contact 2'], [])->getId(); + + $sort = 400; + + $this::assertTrue( + $this->dealContactService->itemsSet( + $dealId, + [ + [ + 'CONTACT_ID' => $contact2Id, + 'SORT' => $sort, + 'IS_PRIMARY' => 'Y', + ], + [ + 'CONTACT_ID' => $contact1Id, + 'SORT' => '100', + 'IS_PRIMARY' => 'N', + ], + ] + + )->isSuccess() + ); + + $this::assertCount(2, $this->dealContactService->itemsGet($dealId)->getDealContacts()); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealContact::delete + * @throws BaseException + * @throws TransportException + */ + public function testDelete(): void + { + $dealId = $this->dealService->add(['TITLE' => 'test deal'])->getId(); + $contact1Id = $this->contactService->add(['NAME' => 'test contact 1'], [])->getId(); + $contact2Id = $this->contactService->add(['NAME' => 'test contact 2'], [])->getId(); + + $this::assertGreaterThanOrEqual( + 1, + $this->dealContactService->add($dealId, $contact1Id, true)->getId() + ); + $this::assertGreaterThanOrEqual( + 1, + $this->dealContactService->add($dealId, $contact2Id, false)->getId() + ); + + $this::assertCount(2, $this->dealContactService->itemsGet($dealId)->getDealContacts()); + + $this::assertTrue($this->dealContactService->delete($dealId, $contact2Id)->isSuccess()); + + $this::assertCount(1, $this->dealContactService->itemsGet($dealId)->getDealContacts()); + } + + public function setUp(): void + { + $this->dealService = Fabric::getServiceBuilder()->getCRMScope()->deal(); + $this->dealContactService = Fabric::getServiceBuilder()->getCRMScope()->dealContact(); + $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php new file mode 100644 index 00000000..a5b73daa --- /dev/null +++ b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php @@ -0,0 +1,137 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Deal\Service; + +use Money\Currencies\ISOCurrencies; +use Money\Currency; +use Money\Formatter\DecimalMoneyFormatter; +use Money\Money; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\CRM\Common\Result\DiscountType; +use Bitrix24\SDK\Services\CRM\Deal\Result\DealProductRowItemResult; +use Bitrix24\SDK\Services\CRM\Deal\Service\Deal; +use Bitrix24\SDK\Services\CRM\Deal\Service\DealProductRows; +use Bitrix24\SDK\Tests\Builders\DemoDataGenerator; +use Bitrix24\SDK\Tests\Integration\Fabric; +use MoneyPHP\Percentage\Percentage; +use PHPUnit\Framework\TestCase; +use Typhoon\Reflection\TyphoonReflector; + +class DealProductRowsTest extends TestCase +{ + private Deal $dealService; + private DealProductRows $dealProductRowsService; + private DecimalMoneyFormatter $decimalMoneyFormatter; + private TyphoonReflector $typhoonReflector; + + public function testAllSystemPropertiesAnnotated(): void + { + $dealId = $this->dealService->add(['TITLE' => 'test deal'])->getId(); + $this->dealProductRowsService->set( + $dealId, + [ + [ + 'PRODUCT_NAME' => sprintf('product name %s', time()), + 'PRICE' => $this->decimalMoneyFormatter->format(new Money(100000, DemoDataGenerator::getCurrency())), + ], + ] + ); + // get response from server with actual keys + $propListFromApi = array_keys($this->dealProductRowsService->get($dealId)->getCoreResponse()->getResponseData()->getResult()['result']['rows'][0]); + // parse keys from phpdoc annotation + $props = $this->typhoonReflector->reflectClass(DealProductRowItemResult::class)->properties(); + $propsFromAnnotations = []; + foreach ($props as $meta) { + if ($meta->isAnnotated() && !$meta->isNative()) { + $propsFromAnnotations[] = $meta->id->name; + } + } + + $this->assertEquals($propListFromApi, $propsFromAnnotations, + sprintf('in phpdocs annotations for class %s cant find fields from actual api response: %s', + DealProductRowItemResult::class, + implode(', ', array_values(array_diff($propListFromApi, $propsFromAnnotations))) + )); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\DealProductRows::set + */ + public function testSet(): void + { + $dealId = $this->dealService->add(['TITLE' => sprintf('test deal %s', time())])->getId(); + $deal = $this->dealService->get($dealId)->deal(); + $price = new Money(100000, $deal->CURRENCY_ID); + $discount = new Money(50012, $deal->CURRENCY_ID); + $this::assertTrue( + $this->dealProductRowsService->set( + $dealId, + [ + [ + 'PRODUCT_NAME' => sprintf('product name %s', time()), + 'PRICE' => $this->decimalMoneyFormatter->format($price), + 'DISCOUNT_TYPE_ID' => 1, + 'DISCOUNT_SUM' => $this->decimalMoneyFormatter->format($discount) + ], + ] + )->isSuccess() + ); + $productRows = $this->dealProductRowsService->get($dealId); + $this->assertCount(1, $productRows->getProductRows()); + $productRow = $productRows->getProductRows()[0]; + $this->assertEquals($price, $productRow->PRICE); + $this->assertEquals(DiscountType::monetary, $productRow->DISCOUNT_TYPE_ID); + $this->assertEquals($discount, $productRow->DISCOUNT_SUM); + $discount = $discount->multiply(100)->divide($this->decimalMoneyFormatter->format($price->add($discount))); + $calculatedPercentage = new Percentage((string)((int)$discount->getAmount() / 100)); + $this->assertEquals($calculatedPercentage, $productRow->DISCOUNT_RATE); + } + + public function testGet(): void + { + $dealId = $this->dealService->add(['TITLE' => sprintf('test deal %s', time())])->getId(); + $deal = $this->dealService->get($dealId)->deal(); + $price = new Money(100000, $deal->CURRENCY_ID); + $discount = new Money(0, $deal->CURRENCY_ID); + $this::assertTrue( + $this->dealProductRowsService->set( + $dealId, + [ + [ + 'PRODUCT_NAME' => sprintf('product name %s', time()), + 'PRICE' => $this->decimalMoneyFormatter->format($price), + ], + ] + )->isSuccess() + ); + $productRows = $this->dealProductRowsService->get($dealId); + $this->assertCount(1, $productRows->getProductRows()); + $productRow = $productRows->getProductRows()[0]; + $this->assertEquals($price, $productRow->PRICE); + $this->assertEquals(DiscountType::percentage, $productRow->DISCOUNT_TYPE_ID); + $this->assertEquals($discount, $productRow->DISCOUNT_SUM); + $this->assertEquals(Percentage::zero(), $productRow->DISCOUNT_RATE); + } + + public function setUp(): void + { + $this->dealService = Fabric::getServiceBuilder()->getCRMScope()->deal(); + $this->dealProductRowsService = Fabric::getServiceBuilder()->getCRMScope()->dealProductRows(); + $this->decimalMoneyFormatter = new DecimalMoneyFormatter(new ISOCurrencies()); + $this->typhoonReflector = TyphoonReflector::build(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Deal/Service/DealTest.php b/tests/Integration/Services/CRM/Deal/Service/DealTest.php new file mode 100644 index 00000000..09fe64a8 --- /dev/null +++ b/tests/Integration/Services/CRM/Deal/Service/DealTest.php @@ -0,0 +1,123 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Deal\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\CRM\Deal\Service\Deal; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\TestCase; + +/** + * Class DealsTest + * + * @package Bitrix24\SDK\Tests\Integration\Services\CRM\Deals\Service + */ +class DealTest extends TestCase +{ + protected Deal $dealService; + + /** + * @throws BaseException + * @throws TransportException + * @covers Deal::add + */ + public function testAdd(): void + { + self::assertGreaterThan(1, $this->dealService->add(['TITLE' => 'test deal'])->getId()); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers Deal::delete + */ + public function testDelete(): void + { + self::assertTrue($this->dealService->delete($this->dealService->add(['TITLE' => 'test deal'])->getId())->isSuccess()); + } + + /** + * @covers Deal::fields + * @throws BaseException + * @throws TransportException + */ + public function testFields(): void + { + self::assertIsArray($this->dealService->fields()->getFieldsDescription()); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers Deal::get + */ + public function testGet(): void + { + self::assertGreaterThan( + 1, + $this->dealService->get($this->dealService->add(['TITLE' => 'test deal'])->getId())->deal()->ID + ); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers Deal::list + */ + public function testList(): void + { + $this->dealService->add(['TITLE' => 'test']); + self::assertGreaterThanOrEqual(1, $this->dealService->list([], [], ['ID', 'TITLE', 'TYPE_ID'])->getDeals()); + } + + public function testUpdate(): void + { + $deal = $this->dealService->add(['TITLE' => 'test']); + $newTitle = 'test2'; + + self::assertTrue($this->dealService->update($deal->getId(), ['TITLE' => $newTitle], [])->isSuccess()); + self::assertEquals($newTitle, $this->dealService->get($deal->getId())->deal()->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->dealService->countByFilter(); + + $newDealsCount = 60; + $deals = []; + for ($i = 1; $i <= $newDealsCount; $i++) { + $deals[] = ['TITLE' => 'TITLE-' . $i]; + } + $cnt = 0; + foreach ($this->dealService->batch->add($deals) as $item) { + $cnt++; + } + self::assertEquals(count($deals), $cnt); + + $after = $this->dealService->countByFilter(); + + $this->assertEquals($before + $newDealsCount, $after); + } + + public function setUp(): void + { + $this->dealService = Fabric::getServiceBuilder()->getCRMScope()->deal(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Deal/Service/DealUserfieldTest.php b/tests/Integration/Services/CRM/Deal/Service/DealUserfieldTest.php new file mode 100644 index 00000000..ff46e856 --- /dev/null +++ b/tests/Integration/Services/CRM/Deal/Service/DealUserfieldTest.php @@ -0,0 +1,151 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Deal\Service; + +use Bitrix24\SDK\Services\CRM\Deal\Service\DealUserfield; +use Bitrix24\SDK\Tests\Integration\Fabric; +use Generator; +use PHPUnit\Framework\TestCase; + +class DealUserfieldTest extends TestCase +{ + protected DealUserfield $userfieldService; + + /** + * @throws \Exception + */ + public function systemUserfieldsDemoDataDataProvider(): Generator + { + yield 'user type id string' => [ + [ + 'FIELD_NAME' => sprintf('%s%s', substr((string)random_int(0, PHP_INT_MAX), 0, 3), time()), + 'EDIT_FORM_LABEL' => [ + 'ru' => 'тест uf тип string', + 'en' => 'test uf type string', + ], + 'LIST_COLUMN_LABEL' => [ + 'ru' => 'тест uf тип string', + 'en' => 'test uf type string', + ], + 'USER_TYPE_ID' => 'string', + 'XML_ID' => 'b24phpsdk_type_string', + 'SETTINGS' => [], + ], + ]; + + mt_srand(); + yield 'user type id integer' => [ + [ + 'FIELD_NAME' => sprintf('%s%s', substr((string)random_int(0, PHP_INT_MAX), 0, 3), time()), + 'EDIT_FORM_LABEL' => [ + 'ru' => 'тест uf тип integer', + 'en' => 'test uf type integer', + ], + 'LIST_COLUMN_LABEL' => [ + 'ru' => 'тест uf тип integer', + 'en' => 'test uf type integer', + ], + 'USER_TYPE_ID' => 'integer', + 'XML_ID' => 'b24phpsdk_type_integer', + 'SETTINGS' => [], + ], + ]; + } + + /** + * @param array $newUserFieldItem + * + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNameIsTooLongException + * @covers ContactUserfield::add + * @dataProvider systemUserfieldsDemoDataDataProvider + */ + public function testAdd(array $newUserFieldItem): void + { + self::assertGreaterThanOrEqual(1, $this->userfieldService->add($newUserFieldItem)->getId()); + } + + /** + * @param array $newUserFieldItem + * + * @dataProvider systemUserfieldsDemoDataDataProvider + * @covers ContactUserfield::delete + */ + public function testDelete(array $newUserFieldItem): void + { + $newUserfieldId = $this->userfieldService->add($newUserFieldItem)->getId(); + $this->assertTrue($this->userfieldService->delete($newUserfieldId)->isSuccess()); + } + + /** + * @param array $newUserFieldItem + * + * @dataProvider systemUserfieldsDemoDataDataProvider + * @covers ContactUserfield::get + */ + public function testGet(array $newUserFieldItem): void + { + $newUserfieldId = $this->userfieldService->add($newUserFieldItem)->getId(); + $ufField = $this->userfieldService->get($newUserfieldId)->userfieldItem(); + $this->assertEquals($newUserfieldId, $ufField->ID); + $this->assertEquals($newUserFieldItem['USER_TYPE_ID'], $ufField->USER_TYPE_ID); + $this->assertEquals('UF_CRM_' . $newUserFieldItem['FIELD_NAME'], $ufField->FIELD_NAME); + $this->assertEquals($newUserFieldItem['XML_ID'], $ufField->XML_ID); + } + + /** + * @param array $newUserFieldItem + * + * @dataProvider systemUserfieldsDemoDataDataProvider + * @covers ContactUserfield::update + */ + public function testUpdate(array $newUserFieldItem): void + { + $newUserfieldId = $this->userfieldService->add($newUserFieldItem)->getId(); + $ufFieldBefore = $this->userfieldService->get($newUserfieldId)->userfieldItem(); + $this->assertEquals($newUserfieldId, $ufFieldBefore->ID); + $this->assertEquals($newUserFieldItem['USER_TYPE_ID'], $ufFieldBefore->USER_TYPE_ID); + $this->assertEquals('UF_CRM_' . $newUserFieldItem['FIELD_NAME'], $ufFieldBefore->FIELD_NAME); + $this->assertEquals($newUserFieldItem['XML_ID'], $ufFieldBefore->XML_ID); + + $this->assertTrue( + $this->userfieldService->update( + $newUserfieldId, + [ + 'EDIT_FORM_LABEL' => $newUserFieldItem['EDIT_FORM_LABEL']['en'] . 'QQQ', + ] + )->isSuccess() + ); + + $ufFieldAfter = $this->userfieldService->get($newUserfieldId)->userfieldItem(); + $this->assertEquals($ufFieldBefore->EDIT_FORM_LABEL['en'] . 'QQQ', $ufFieldAfter->EDIT_FORM_LABEL['en']); + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @covers \Bitrix24\SDK\Services\CRM\Contact\Service\ContactUserfield::list + */ + public function testList(): void + { + $ufFields = $this->userfieldService->list([], []); + $this->assertGreaterThanOrEqual(0, count($ufFields->getUserfields())); + } + + public function setUp(): void + { + $this->userfieldService = Fabric::getServiceBuilder()->getCRMScope()->dealUserfield(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Deal/Service/DealUserfieldUseCaseTest.php b/tests/Integration/Services/CRM/Deal/Service/DealUserfieldUseCaseTest.php new file mode 100644 index 00000000..4e90aa58 --- /dev/null +++ b/tests/Integration/Services/CRM/Deal/Service/DealUserfieldUseCaseTest.php @@ -0,0 +1,101 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Deal\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\CRM\Deal\Service\Deal; +use Bitrix24\SDK\Services\CRM\Deal\Service\DealUserfield; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\TestCase; + +class DealUserfieldUseCaseTest extends TestCase +{ + protected Deal $dealService; + protected DealUserfield $dealUserfieldService; + protected int $dealUserfieldId; + + /** + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Deal\Service\Deal::add + */ + public function testOperationsWithUserfieldFromDealItem(): void + { + // get userfield metadata + $ufMetadata = $this->dealUserfieldService->get($this->dealUserfieldId)->userfieldItem(); + $ufOriginalFieldName = $ufMetadata->getOriginalFieldName(); + $ufFieldName = $ufMetadata->FIELD_NAME; + + // add deal with uf value + $fieldNameValue = 'test field value'; + $newDealId = $this->dealService->add( + [ + 'TITLE' => 'test deal', + $ufFieldName => $fieldNameValue, + ] + )->getId(); + $deal = $this->dealService->get($newDealId)->deal(); + $this->assertEquals($fieldNameValue, $deal->getUserfieldByFieldName($ufOriginalFieldName)); + + // update deal userfield value + $newUfValue = 'test 2'; + $this->assertTrue( + $this->dealService->update( + $deal->ID, + [ + $ufFieldName => $newUfValue, + ] + )->isSuccess() + ); + $updatedDeal = $this->dealService->get($deal->ID)->deal(); + $this->assertEquals($newUfValue, $updatedDeal->getUserfieldByFieldName($ufOriginalFieldName)); + } + + /** + * @throws \Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNameIsTooLongException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function setUp(): void + { + $this->dealService = Fabric::getServiceBuilder()->getCRMScope()->deal(); + $this->dealUserfieldService = Fabric::getServiceBuilder()->getCRMScope()->dealUserfield(); + + $this->dealUserfieldId = $this->dealUserfieldService->add( + [ + 'FIELD_NAME' => sprintf('%s%s', substr((string)random_int(0, PHP_INT_MAX), 0, 3), time()), + 'EDIT_FORM_LABEL' => [ + 'ru' => 'тест uf тип string', + 'en' => 'test uf type string', + ], + 'LIST_COLUMN_LABEL' => [ + 'ru' => 'тест uf тип string', + 'en' => 'test uf type string', + ], + 'USER_TYPE_ID' => 'string', + 'XML_ID' => 'b24phpsdk_type_string', + 'SETTINGS' => [ + 'DEFAULT_VALUE' => 'hello world', + ], + ] + )->getId(); + } + + public function tearDown(): void + { + $this->dealUserfieldService->delete($this->dealUserfieldId); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Duplicates/Service/DuplicateTest.php b/tests/Integration/Services/CRM/Duplicates/Service/DuplicateTest.php new file mode 100644 index 00000000..18282c1f --- /dev/null +++ b/tests/Integration/Services/CRM/Duplicates/Service/DuplicateTest.php @@ -0,0 +1,89 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Duplicates\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\Duplicates\Service\Duplicate; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\TestCase; + +class DuplicateTest extends TestCase +{ + protected Contact $contactService; + protected Duplicate $duplicate; + + /** + * @return void + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Duplicates\Service\Duplicate::findByEmail + */ + public function testDuplicatesByEmailNotFound(): void + { + $res = $this->duplicate->findByEmail([sprintf('%s@gmail.com', time())]); + $this->assertFalse($res->hasDuplicateContacts()); + $this->assertFalse($res->hasOneContact()); + $this->assertCount(0, $res->getContactsId()); + } + + /** + * @return void + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Duplicates\Service\Duplicate::findByEmail + */ + public function testDuplicatesByEmailOneItemFound(): void + { + $email = sprintf('%s@gmail.com', time()); + $b24ContactId = $this->contactService->add([ + 'NAME' => 'Test', + 'LAST_NAME' => 'Test', + 'EMAIL' => [ + [ + 'VALUE' => $email, + 'TYPE' => 'WORK' + ] + ] + ])->getId(); + + $res = $this->duplicate->findByEmail([$email]); + $this->assertFalse($res->hasDuplicateContacts()); + $this->assertTrue($res->hasOneContact()); + $this->assertCount(1, $res->getContactsId()); + } + + /** + * @return void + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Duplicates\Service\Duplicate::findByPhone + */ + public function testDuplicatesByPhoneNotFound(): void + { + $res = $this->duplicate->findByPhone([sprintf('+1%s', time())]); + $this->assertFalse($res->hasDuplicateContacts()); + $this->assertFalse($res->hasOneContact()); + $this->assertCount(0, $res->getContactsId()); + } + + + public function setUp(): void + { + $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); + $this->duplicate = Fabric::getServiceBuilder()->getCRMScope()->duplicate(); + + } +} \ No newline at end of file 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..23bfd35c --- /dev/null +++ b/tests/Integration/Services/CRM/Lead/Service/BatchTest.php @@ -0,0 +1,106 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Lead\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\CRM\Lead\Service\Lead; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\TestCase; + +/** + * Class BatchTest + * + * @package Bitrix24\SDK\Tests\Integration\Services\CRM\Lead\Service + */ +class BatchTest extends TestCase +{ + protected Lead $leadService; + + /** + * @testdox Batch list leads + * @covers \Bitrix24\SDK\Services\CRM\Lead\Service\Batch::list() + * @throws BaseException + * @throws TransportException + */ + public function testBatchList(): void + { + $itemId = $this->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..83ba1381 --- /dev/null +++ b/tests/Integration/Services/CRM/Lead/Service/LeadTest.php @@ -0,0 +1,128 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Lead\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\CRM\Lead\Service\Lead; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\TestCase; + +/** + * Class LeadTest + * + * @package Bitrix24\SDK\Tests\Integration\Services\CRM\Lead\Service + */ +class LeadTest extends TestCase +{ + protected Lead $leadService; + + /** + * @throws BaseException + * @throws TransportException + * @covers Lead::add + */ + public function testAdd(): void + { + self::assertGreaterThan(1, $this->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/CRM/Products/Service/ProductsTest.php b/tests/Integration/Services/CRM/Products/Service/ProductsTest.php new file mode 100644 index 00000000..be7cd637 --- /dev/null +++ b/tests/Integration/Services/CRM/Products/Service/ProductsTest.php @@ -0,0 +1,163 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Products\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\CRM\Product\Service\Product; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\TestCase; + +class ProductsTest extends TestCase +{ + protected Product $productService; + + /** + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Product\Service\Product::add + */ + public function testAdd(): void + { + self::assertGreaterThan(1, $this->productService->add(['NAME' => 'test product'])->getId()); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Product\Service\Product::delete + */ + public function testDelete(): void + { + self::assertTrue($this->productService->delete($this->productService->add(['NAME' => 'test product'])->getId())->isSuccess()); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Product\Service\Product::get + */ + public function testGet(): void + { + $product = [ + 'NAME' => 'test product', + ]; + $addProductResult = $this->productService->get($this->productService->add($product)->getId()); + self::assertGreaterThan( + 1, + $addProductResult->product()->ID + ); + self::assertEquals( + $product['NAME'], + $addProductResult->product()->NAME + ); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Product\Service\Product::fields + * @throws BaseException + * @throws TransportException + */ + public function testFields(): void + { + self::assertIsArray($this->productService->fields()->getFieldsDescription()); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Product\Service\Product::list + */ + public function testList(): void + { + $this->productService->add(['NAME' => 'test']); + self::assertGreaterThanOrEqual(1, $this->productService->list([], [], ['ID', 'NAME'])->getProducts()); + } + + /** + * @throws BaseException + * @throws TransportException + * @covers \Bitrix24\SDK\Services\CRM\Product\Service\Product::update + */ + public function testUpdate(): void + { + $product = $this->productService->add(['NAME' => 'test']); + $newName = 'test2'; + + self::assertTrue($this->productService->update($product->getId(), ['NAME' => $newName])->isSuccess()); + self::assertEquals($newName, $this->productService->get($product->getId())->product()->NAME); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Product\Service\Batch::list() + * @throws BaseException + * @throws TransportException + */ + public function testBatchList(): void + { + $this->productService->add(['NAME' => 'test product']); + $cnt = 0; + + foreach ($this->productService->batch->list([], ['>ID' => '1'], ['ID', 'NAME'], 1) as $item) { + $cnt++; + } + self::assertGreaterThanOrEqual(1, $cnt); + } + + /** + * @covers \Bitrix24\SDK\Services\CRM\Product\Service\Batch::add() + */ + public function testBatchAdd(): void + { + $products = []; + for ($i = 1; $i < 60; $i++) { + $products[] = ['NAME' => 'NAME-' . $i]; + } + $cnt = 0; + foreach ($this->productService->batch->add($products) as $item) { + $cnt++; + } + + self::assertEquals(count($products), $cnt); + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @covers \Bitrix24\SDK\Services\CRM\Product\Service\Product::countByFilter + */ + public function testCountByFilter(): void + { + $productsCountBefore = $this->productService->countByFilter(); + $newProductsCount = 60; + $products = []; + for ($i = 1; $i <= $newProductsCount; $i++) { + $products[] = ['NAME' => 'NAME-' . $i]; + } + $cnt = 0; + foreach ($this->productService->batch->add($products) as $item) { + $cnt++; + } + + self::assertEquals(count($products), $cnt); + + $productsCountAfter = $this->productService->countByFilter(); + $this->assertEquals($productsCountBefore + $newProductsCount, $productsCountAfter); + } + + public function setUp(): void + { + $this->productService = Fabric::getServiceBuilder()->getCRMScope()->product(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/CRM/Userfield/Service/UserfieldTest.php b/tests/Integration/Services/CRM/Userfield/Service/UserfieldTest.php new file mode 100644 index 00000000..b6391a3a --- /dev/null +++ b/tests/Integration/Services/CRM/Userfield/Service/UserfieldTest.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\CRM\Userfield\Service; + +use Bitrix24\SDK\Services\CRM\Userfield\Service\Userfield; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\TestCase; + +class UserfieldTest extends TestCase +{ + protected Userfield $userfieldService; + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @covers \Bitrix24\SDK\Services\CRM\Userfield\Service\Userfield::fields + */ + public function testFields(): void + { + self::assertIsArray($this->userfieldService->fields()->getFieldsDescription()); + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @covers \Bitrix24\SDK\Services\CRM\Userfield\Service\Userfield::enumerationFields + */ + public function testEnumerationFields(): void + { + self::assertIsArray($this->userfieldService->enumerationFields()->getFieldsDescription()); + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @covers \Bitrix24\SDK\Services\CRM\Userfield\Service\Userfield::settingsFields + */ + public function testSettingsFields(): void + { + foreach ($this->userfieldService->types()->getTypes() as $typeItem) { + self::assertIsArray($this->userfieldService->settingsFields($typeItem->ID)->getFieldsDescription()); + } + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @covers \Bitrix24\SDK\Services\CRM\Userfield\Service\Userfield::types + */ + public function testTypes(): void + { + $ufTypes = $this->userfieldService->types(); + $this->assertGreaterThan(10, $ufTypes->getTypes()); + } + + + public function setUp(): void + { + $this->userfieldService = Fabric::getServiceBuilder()->getCRMScope()->userfield(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/Catalog/Catalog/Service/CatalogTest.php b/tests/Integration/Services/Catalog/Catalog/Service/CatalogTest.php new file mode 100644 index 00000000..47e03abb --- /dev/null +++ b/tests/Integration/Services/Catalog/Catalog/Service/CatalogTest.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\Catalog\Catalog\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\Catalog\Catalog\Service\Catalog; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Catalog::class)] +class CatalogTest extends TestCase +{ + protected Catalog $service; + + /** + * @throws BaseException if there is a base exception occurred + * @throws TransportException if there is a transport exception occurred + */ + #[TestDox('Test Catalog::fields method')] + public function testFields(): void + { + $this->assertIsArray($this->service->fields()->getFieldsDescription()); + } + + /** + * @throws BaseException if there is a base exception occurred + * @throws TransportException if there is a transport exception occurred + */ + #[TestDox('Test Catalog::list method')] + public function testList(): void + { + $this->assertGreaterThan(1, $this->service->list([], [], [], 1)->getCatalogs()[0]->id); + } + + /** + * @throws BaseException if there is a general exception. + * @throws TransportException if there is an exception during transport. + */ + #[TestDox('Test Catalog::get method')] + public function testGet(): void + { + $catalog = $this->service->list([], [], [], 1)->getCatalogs()[0]; + $this->assertEquals($catalog->id, $this->service->get($catalog->id)->catalog()->id); + } + + protected function setUp(): void + { + $this->service = Fabric::getServiceBuilder()->getCatalogScope()->catalog(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/Catalog/Product/Service/ProductTest.php b/tests/Integration/Services/Catalog/Product/Service/ProductTest.php new file mode 100644 index 00000000..3e514c0f --- /dev/null +++ b/tests/Integration/Services/Catalog/Product/Service/ProductTest.php @@ -0,0 +1,158 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\Catalog\Product\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\Catalog\Catalog\Service\Catalog; +use Bitrix24\SDK\Services\Catalog\Common\ProductType; +use Bitrix24\SDK\Services\Catalog\Product\Service\Product; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversClass(Product::class)] +class ProductTest extends TestCase +{ + protected Product $productService; + + protected Catalog $catalogService; + + /** + * @throws BaseException + * @throws TransportException + */ + #[TestDox('test Product::fieldsByFilter')] + public function testFieldsByFilter(): void + { + $iblockId = $this->catalogService->list([], [], [], 1)->getCatalogs()[0]->iblockId; + $this->assertIsArray($this->productService->fieldsByFilter( + $iblockId, + ProductType::simple + )->getFieldsDescription()); + } + + /** + * @throws BaseException If there is a base exception thrown during the product addition process. + * @throws TransportException If there is a transport exception thrown during the product addition process. + */ + #[TestDox('test Product::add')] + public function testAdd(): void + { + $iblockId = $this->catalogService->list([], [], [], 1)->getCatalogs()[0]->iblockId; + $fields = [ + 'iblockId' => $iblockId, + 'name' => sprintf('test product name %s', time()), + '' + ]; + $productResult = $this->productService->add($fields); + $this->assertEquals($fields['name'], $productResult->product()->name); + $this->productService->delete($productResult->product()->id); + } + + /** + * @throws BaseException If there is a base exception thrown during the product retrieval process. + * @throws TransportException If there is a transport exception thrown during the product retrieval process. + */ + #[TestDox('test Product::get')] + public function testGet(): void + { + $iblockId = $this->catalogService->list([], [], [], 1)->getCatalogs()[0]->iblockId; + $fields = [ + 'iblockId' => $iblockId, + 'name' => sprintf('test product name %s', time()), + ]; + $productResult = $this->productService->add($fields); + $productGet = $this->productService->get($productResult->product()->id); + $this->assertEquals($productResult->product()->id, $productGet->product()->id); + $this->productService->delete($productGet->product()->id); + } + + /** + * Deletes a product from the system and asserts that the product was deleted successfully. + * + * @throws BaseException If there is a base exception thrown during the product deletion process. + * @throws TransportException If there is a transport exception thrown during the product deletion process. + */ + #[TestDox('test Product::delete')] + public function testDelete(): void + { + $iblockId = $this->catalogService->list([], [], [], 1)->getCatalogs()[0]->iblockId; + $fields = [ + 'iblockId' => $iblockId, + 'name' => sprintf('test product name %s', time()), + ]; + $productResult = $this->productService->add($fields); + $productGet = $this->productService->get($productResult->product()->id); + $this->assertEquals($productResult->product()->id, $productGet->product()->id); + $this->productService->delete($productGet->product()->id); + + $productsResult = $this->productService->list( + [ + 'id', + 'iblockId' + ], + [ + 'id' => $productGet->product()->id, + 'iblockId' => $iblockId + ], + [ + 'id' => 'asc' + ], + 1 + ); + $this->assertCount(0, $productsResult->getProducts()); + } + + /** + * Retrieves a list of products that match the specified filter criteria and asserts that the expected number of products is returned. + * + * @throws BaseException If there is a base exception thrown during the process of listing products. + * @throws TransportException If there is a transport exception thrown during the process of listing products. + */ + #[TestDox('test Product::list')] + public function testList():void + { + $iblockId = $this->catalogService->list([], [], [], 1)->getCatalogs()[0]->iblockId; + $fields = [ + 'iblockId' => $iblockId, + 'name' => sprintf('test product name %s', time()), + ]; + $productResult = $this->productService->add($fields); + $productGet = $this->productService->get($productResult->product()->id); + $this->assertEquals($productResult->product()->id, $productGet->product()->id); + $productsResult = $this->productService->list( + [ + 'id', + 'iblockId' + ], + [ + 'id' => $productGet->product()->id, + 'iblockId' => $iblockId + ], + [ + 'id' => 'asc' + ], + 1 + ); + $this->assertCount(1, $productsResult->getProducts()); + } + + protected function setUp(): void + { + $this->productService = Fabric::getServiceBuilder()->getCatalogScope()->product(); + $this->catalogService = Fabric::getServiceBuilder()->getCatalogScope()->catalog(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/IM/Service/NotifyTest.php b/tests/Integration/Services/IM/Service/NotifyTest.php new file mode 100644 index 00000000..a90b42e3 --- /dev/null +++ b/tests/Integration/Services/IM/Service/NotifyTest.php @@ -0,0 +1,169 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\IM\Notify\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\IM\Notify\Service\Notify; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Notify::class)] +class NotifyTest extends TestCase +{ + private Notify $imNotifyService; + + /** + * @throws BaseException + * @throws TransportException + */ + #[Test] + #[TestDox('Test send notification from system')] + public function testFromSystem(): void + { + $addedItemResult = $this->imNotifyService->fromSystem( + (int)$this->imNotifyService->core->call('PROFILE')->getResponseData()->getResult()['ID'], + sprintf('Test message at %s', time()) + ); + $this->assertGreaterThan(0, $addedItemResult->getId()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + #[Test] + #[TestDox('Test send notification from personal')] + public function testFromPersonal(): void + { + $addedItemResult = $this->imNotifyService->fromPersonal( + (int)$this->imNotifyService->core->call('PROFILE')->getResponseData()->getResult()['ID'], + sprintf('Test message at %s', time()) + ); + $this->assertGreaterThan(0, $addedItemResult->getId()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + #[Test] + #[TestDox('Test delete notification')] + public function testDelete(): void + { + $addedItemResult = $this->imNotifyService->fromSystem( + (int)$this->imNotifyService->core->call('PROFILE')->getResponseData()->getResult()['ID'], + sprintf('Test message for delete at %s', time()) + ); + $this->assertGreaterThan(0, $addedItemResult->getId()); + $this->assertTrue($this->imNotifyService->delete($addedItemResult->getId())->isSuccess()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + #[Test] + #[TestDox('Test mark as read notification')] + public function testMarkAsRead(): void + { + $addedItemResult = $this->imNotifyService->fromSystem( + (int)$this->imNotifyService->core->call('PROFILE')->getResponseData()->getResult()['ID'], + sprintf('Test message for mark as read at %s', time()) + ); + $this->assertGreaterThan(0, $addedItemResult->getId()); + $this->assertTrue($this->imNotifyService->markAsRead($addedItemResult->getId())->isSuccess()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + #[Test] + #[TestDox('Test mark messages as read')] + public function testMarkMessagesAsRead(): void + { + $messageIds = []; + for ($i = 0; $i < 5; $i++) { + $messageIds[] = $this->imNotifyService->fromSystem( + (int)$this->imNotifyService->core->call('PROFILE')->getResponseData()->getResult()['ID'], + sprintf('Test message for mark as read at %s', time()) + )->getId(); + } + + $this->assertTrue($this->imNotifyService->markMessagesAsRead($messageIds)->isSuccess()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + #[Test] + #[TestDox('Test mark messages as unread')] + public function testMarkMessagesAsUnread(): void + { + $messageIds = []; + for ($i = 0; $i < 5; $i++) { + $messageIds[] = $this->imNotifyService->fromSystem( + (int)$this->imNotifyService->core->call('PROFILE')->getResponseData()->getResult()['ID'], + sprintf('Test message for mark as read at %s', time()) + )->getId(); + } + + $this->assertTrue($this->imNotifyService->markMessagesAsRead($messageIds)->isSuccess()); + $this->assertTrue($this->imNotifyService->markMessagesAsUnread($messageIds)->isSuccess()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + #[Test] + #[TestDox('Test mark messages as answered')] + public function testAnswer(): void + { + $addedItemResult = $this->imNotifyService->fromPersonal( + (int)$this->imNotifyService->core->call('PROFILE')->getResponseData()->getResult()['ID'], + sprintf('Test message at %s', time()) + ); + $this->assertGreaterThan(0, $addedItemResult->getId()); + + $this->imNotifyService->answer($addedItemResult->getId(), 'reply text'); + } + + /** + * @throws BaseException + * @throws TransportException + */ + #[Test] + #[TestDox('Test Interaction with notification buttons')] + public function testConfirm(): void + { + $addedItemResult = $this->imNotifyService->fromPersonal( + (int)$this->imNotifyService->core->call('PROFILE')->getResponseData()->getResult()['ID'], + sprintf('Test message at %s', time()) + ); + $this->assertGreaterThan(0, $addedItemResult->getId()); + + $this->imNotifyService->confirm($addedItemResult->getId(), true); + } + + protected function setUp(): void + { + $this->imNotifyService = Fabric::getServiceBuilder()->getIMScope()->notify(); + } +} \ 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..9f3b564e --- /dev/null +++ b/tests/Integration/Services/IMOpenLines/Service/NetworkTest.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\IMOpenLines\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\IMOpenLines\Service\Network; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Network::class)] +class NetworkTest extends TestCase +{ + private Network $networkService; + + /** + * @throws BaseException + * @throws TransportException + */ + #[TestDox('test get agreements list')] + public function testJoin(): void + { + $joinOpenLineResult = $this->networkService->join(Fabric::getOpenLineCode()); + $this->assertGreaterThanOrEqual(1, $joinOpenLineResult->getId()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + #[TestDox('test get agreements list')] + public function testMessageAdd(): void + { + $addedMessageItemResult = $this->networkService->messageAdd( + Fabric::getOpenLineCode(), + (int)$this->networkService->core->call('PROFILE')->getResponseData()->getResult()['ID'], + sprintf('Test message at %s', time()) + ); + + $this->assertTrue($addedMessageItemResult->isSuccess()); + } + + protected 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..09100776 --- /dev/null +++ b/tests/Integration/Services/Main/Service/MainTest.php @@ -0,0 +1,117 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\Main\Service; + +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException; +use Bitrix24\SDK\Services\Main\Service\Main; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Main::class)] +class MainTest extends TestCase +{ + private Main $mainService; + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGetServerTime(): void + { + $this->mainService->getServerTime()->time(); + $this->assertTrue(true); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testGetCurrentUserProfile(): void + { + $userProfileItemResult = $this->mainService->getCurrentUserProfile()->getUserProfile(); + $this->assertTrue($userProfileItemResult->ADMIN); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testIsUserIsAdmin(): void + { + $this->assertTrue($this->mainService->isCurrentUserHasAdminRights()->isAdmin()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testMethodGetInformationForNonExistsMethod(): void + { + $this->assertFalse($this->mainService->getMethodAffordability('app.info1')->isAvailable()); + $this->assertFalse($this->mainService->getMethodAffordability('app.info1')->isExisting()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + public function testApplicationInfo(): void + { + $this->assertIsString($this->mainService->getApplicationInfo()->applicationInfo()->LICENSE); + } + + /** + * @throws BaseException + * @throws TransportException + * @throws UnknownScopeCodeException + */ + public function testGetAvailableScope(): void + { + $scope = new Scope($this->mainService->getAvailableScope()->getResponseData()->getResult()); + $this->assertIsArray($scope->getScopeCodes()); + } + + /** + * @throws BaseException + * @throws TransportException + * @throws 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()) + ); + } + + /** + * @throws BaseException + * @throws TransportException + */ + #[TestDox('test methods list')] + public function testGetAvailableMethods(): void + { + $this->assertIsArray($this->mainService->getAvailableMethods()->getResponseData()->getResult()); + } + + protected function setUp(): void + { + $this->mainService = Fabric::getServiceBuilder()->getMainScope()->main(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/Placement/Service/PlacementTest.php b/tests/Integration/Services/Placement/Service/PlacementTest.php new file mode 100644 index 00000000..69714442 --- /dev/null +++ b/tests/Integration/Services/Placement/Service/PlacementTest.php @@ -0,0 +1,112 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\Placement\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\IM\Notify\Service\Notify; +use Bitrix24\SDK\Services\IMOpenLines\Service\Network; +use Bitrix24\SDK\Services\Placement\Result\PlacementLocationItemResult; +use Bitrix24\SDK\Services\Placement\Service\Placement; +use Bitrix24\SDK\Services\Placement\Service\PlacementLocationCode; +use Bitrix24\SDK\Services\Telephony\Call\Service\Call; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Placement::class)] +class PlacementTest extends TestCase +{ + private Placement $placementService; + + #[Test] + #[TestDox('Test method bind')] + public function testBind(): void + { + /** + * @var PlacementLocationItemResult[] $placements + */ + $placements = $this->placementService->get()->getPlacementsLocationInformation(); + foreach ($placements as $placement) { + $this->assertGreaterThanOrEqual(0, $this->placementService->unbind($placement->placement)->getDeletedPlacementHandlersCount()); + } + + $placementBindResult = $this->placementService->bind( + PlacementLocationCode::CRM_CONTACT_DETAIL_TAB, + 'https://bitrix24test.com', [ + 'en' => [ + 'TITLE' => 'test app' + ] + ]); + $this->assertTrue($placementBindResult->isSuccess()); + $placement = $this->placementService->get()->getPlacementsLocationInformation()[0]; + $this->assertEquals(PlacementLocationCode::CRM_CONTACT_DETAIL_TAB, $placement->placement); + $this->placementService->unbind(PlacementLocationCode::CRM_CONTACT_DETAIL_TAB)->getDeletedPlacementHandlersCount(); + } + + #[Test] + #[TestDox('Test method unbind')] + public function testUnbind(): void + { + /** + * @var PlacementLocationItemResult[] $placements + */ + $placements = $this->placementService->get()->getPlacementsLocationInformation(); + foreach ($placements as $placement) { + $this->assertGreaterThanOrEqual(0, $this->placementService->unbind($placement->placement)->getDeletedPlacementHandlersCount()); + } + + $placementBindResult = $this->placementService->bind( + PlacementLocationCode::CRM_CONTACT_DETAIL_TAB, + 'https://bitrix24test.com', [ + 'en' => [ + 'TITLE' => 'test app' + ] + ]); + $this->assertTrue($placementBindResult->isSuccess()); + $placement = $this->placementService->get()->getPlacementsLocationInformation()[0]; + $this->assertEquals(PlacementLocationCode::CRM_CONTACT_DETAIL_TAB, $placement->placement); + + $this->placementService->unbind(PlacementLocationCode::CRM_CONTACT_DETAIL_TAB)->getDeletedPlacementHandlersCount(); + + } + + #[Test] + #[TestDox('Test method get')] + public function testGet(): void + { + $placementsLocationInformationResult = $this->placementService->get(); + $this->assertGreaterThanOrEqual(0, count($placementsLocationInformationResult->getPlacementsLocationInformation())); + } + + /** + * @throws BaseException + * @throws TransportException + */ + #[Test] + #[TestDox('Test method list')] + public function testList(): void + { + $placementLocationCodesResult = $this->placementService->list(); + $this->assertGreaterThanOrEqual(0, count($placementLocationCodesResult->getLocationCodes())); + } + + protected function setUp(): void + { + $this->placementService = Fabric::getServiceBuilder(true)->getPlacementScope()->placement(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/Call/Service/CallTest.php b/tests/Integration/Services/Telephony/Call/Service/CallTest.php new file mode 100644 index 00000000..e1383fca --- /dev/null +++ b/tests/Integration/Services/Telephony/Call/Service/CallTest.php @@ -0,0 +1,141 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\Telephony\Call\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\Telephony\Call\Service\Call; +use Bitrix24\SDK\Services\Telephony\Common\CallType; +use Bitrix24\SDK\Services\Telephony\Common\CrmEntityType; +use Bitrix24\SDK\Services\Telephony\Common\TelephonyCallStatusCode; +use Bitrix24\SDK\Services\Telephony\Common\TranscriptMessage; +use Bitrix24\SDK\Services\Telephony\Common\TranscriptMessageSide; +use Bitrix24\SDK\Services\Telephony\ExternalCall\Service\ExternalCall; +use Bitrix24\SDK\Tests\Integration\Fabric; +use Carbon\CarbonImmutable; +use Generator; +use Money\Currency; +use Money\Money; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; +use Random\RandomException; + +#[CoversClass(Call::class)] +class CallTest extends TestCase +{ + private Call $call; + + private ExternalCall $externalCall; + + /** + * @throws RandomException + * @throws InvalidArgumentException + * @throws BaseException + * @throws TransportException + */ + public static function callIdDataProvider(): Generator + { + $externalCall = Fabric::getServiceBuilder()->getTelephonyScope()->externalCall(); + $serviceBuilder = Fabric::getServiceBuilder(); + + $innerPhoneNumber = '123'; + // phone number to call + $phoneNumber = '7978' . random_int(1000000, 9999999); + $currentB24UserId = $serviceBuilder->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()->ID; + // set inner phone number + $serviceBuilder->getUserScope()->user()->update( + $currentB24UserId, + [ + 'UF_PHONE_INNER' => $innerPhoneNumber + ] + ); + $externalCallRegisteredResult = $externalCall->register( + $innerPhoneNumber, + $currentB24UserId, + $phoneNumber, + CarbonImmutable::now(), + CallType::outbound, + true, + true, + '3333', + null, + CrmEntityType::contact + + ); + + yield 'default callId' => [ + $externalCallRegisteredResult->getExternalCallRegistered()->CALL_ID, + $currentB24UserId + ]; + } + + /** + * @throws TransportException + * @throws BaseException + */ + #[Test] + #[DataProvider('callIdDataProvider')] + #[TestDox('Method tests attachTranscription method')] + public function testFinishWithUserId(string $callId, int $currentB24UserId): void + { + $money = new Money(30000, new Currency('USD')); + $duration = 100; + + $this->externalCall->finishForUserId( + $callId, + $currentB24UserId, + $duration, + $money, + TelephonyCallStatusCode::successful, + true + ); + + $filename = dirname(__DIR__, 2) . '/call-record-test.mp3'; + $this->externalCall->attachCallRecordInBase64( + $callId, + $filename + ); + + $transcriptAttachedResult = $this->call->attachTranscription( + $callId, + $money, + [ + new TranscriptMessage(TranscriptMessageSide::user, 1, 5, "We're no strangers to love"), + new TranscriptMessage(TranscriptMessageSide::client, 5, 10, "You know the rules and so do I (do I)"), + new TranscriptMessage(TranscriptMessageSide::user, 10, 15, "A full commitment's what I'm thinking of"), + new TranscriptMessage(TranscriptMessageSide::client, 15, 20, "You wouldn't get this from any other guy"), + new TranscriptMessage(TranscriptMessageSide::user, 20, 25, "I just wanna tell you how I'm feeling"), + new TranscriptMessage(TranscriptMessageSide::client, 25, 30, "Gotta make you understand"), + new TranscriptMessage(TranscriptMessageSide::user, 30, 35, "Never gonna give you up"), + new TranscriptMessage(TranscriptMessageSide::client, 35, 40, "Never gonna let you down"), + new TranscriptMessage(TranscriptMessageSide::user, 40, 45, "Never gonna run around and desert you"), + new TranscriptMessage(TranscriptMessageSide::client, 45, 50, "Never gonna make you cry"), + new TranscriptMessage(TranscriptMessageSide::user, 50, 55, "Never gonna say goodbye"), + new TranscriptMessage(TranscriptMessageSide::client, 55, 60, "Never gonna tell a lie and hurt you"), + ] + ); + + $this->assertGreaterThan(0, $transcriptAttachedResult->getTranscriptAttachItem()->TRANSCRIPT_ID); + } + + protected function setUp(): void + { + $this->call = Fabric::getServiceBuilder(true)->getTelephonyScope()->call(); + $this->externalCall = Fabric::getServiceBuilder(true)->getTelephonyScope()->externalCall(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php b/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php new file mode 100644 index 00000000..6968f76e --- /dev/null +++ b/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php @@ -0,0 +1,224 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\Telephony\ExternalCall\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\ServiceBuilder; +use Bitrix24\SDK\Services\Telephony\Common\CallType; +use Bitrix24\SDK\Services\Telephony\Common\CrmEntityType; +use Bitrix24\SDK\Services\Telephony\Common\TelephonyCallStatusCode; +use Bitrix24\SDK\Services\Telephony\ExternalCall\Service\ExternalCall; +use Bitrix24\SDK\Tests\Integration\Fabric; +use Carbon\CarbonImmutable; +use Generator; +use Money\Currency; +use Money\Money; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; +use Random\RandomException; + +#[CoversClass(ExternalCall::class)] +class ExternalCallTest extends TestCase +{ + private ExternalCall $externalCall; + + private ServiceBuilder $serviceBuilder; + + /** + * @throws RandomException + * @throws InvalidArgumentException + * @throws BaseException + * @throws TransportException + */ + public static function callIdDataProvider(): Generator + { + $externalCall = Fabric::getServiceBuilder()->getTelephonyScope()->externalCall(); + $serviceBuilder = Fabric::getServiceBuilder(); + + $innerPhoneNumber = '123'; + // phone number to call + $phoneNumber = '7978' . random_int(1000000, 9999999); + $currentB24UserId = $serviceBuilder->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()->ID; + // set inner phone number + $serviceBuilder->getUserScope()->user()->update( + $currentB24UserId, + [ + 'UF_PHONE_INNER' => $innerPhoneNumber + ] + ); + $externalCallRegisteredResult = $externalCall->register( + $innerPhoneNumber, + $currentB24UserId, + $phoneNumber, + CarbonImmutable::now(), + CallType::outbound, + true, + true, + '3333', + null, + CrmEntityType::contact + + ); + + yield 'default callId' => [ + $externalCallRegisteredResult->getExternalCallRegistered()->CALL_ID, + $currentB24UserId + ]; + } + + /** + * @throws BaseException + * @throws TransportException + */ + #[Test] + #[TestDox('Method registers a call in Bitrix24.')] + public function testRegister(): void + { + $innerPhoneNumber = '123'; + // phone number to call + $phoneNumber = '79780000000'; + + $currentB24UserId = $this->serviceBuilder->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()->ID; + // set inner phone number + $this->serviceBuilder->getUserScope()->user()->update( + $currentB24UserId, + [ + 'UF_PHONE_INNER' => $innerPhoneNumber + ] + ); + + $externalCallRegisteredResult = $this->externalCall->register( + $innerPhoneNumber, + $currentB24UserId, + $phoneNumber, + CarbonImmutable::now(), + CallType::outbound, + true, + true, + '3333', + null, + CrmEntityType::contact + + ); + + $this->assertNotEmpty($externalCallRegisteredResult->getExternalCallRegistered()->CALL_ID); + } + + /** + * @throws BaseException + * @throws TransportException + */ + #[Test] + #[DataProvider('callIdDataProvider')] + #[TestDox('Method tests show call ui')] + public function testShow(string $callId, int $currentB24UserId): void + { + $this->assertTrue($this->externalCall->show($callId, [$currentB24UserId])->isSuccess()); + } + + #[Test] + #[DataProvider('callIdDataProvider')] + #[TestDox('Method tests hide call ui')] + public function testHide(string $callId, int $currentB24UserId): void + { + $this->assertTrue($this->externalCall->hide($callId, [$currentB24UserId])->isSuccess()); + } + + /** + * @throws TransportException + * @throws BaseException + */ + #[Test] + #[DataProvider('callIdDataProvider')] + #[TestDox('Method tests finishForUserId method')] + public function testFinishWithUserId(string $callId, int $currentB24UserId): void + { + $money = new Money(10000, new Currency('USD')); + $duration = 100; + + $externalCallFinishedResult = $this->externalCall->finishForUserId( + $callId, + $currentB24UserId, + $duration, + $money, + TelephonyCallStatusCode::successful, + true + ); + + $this->assertTrue($externalCallFinishedResult->getExternalCallFinished()->COST->equals($money)); + $this->assertEquals($externalCallFinishedResult->getExternalCallFinished()->CALL_DURATION, $duration); + + } + + #[Test] + #[DataProvider('callIdDataProvider')] + #[TestDox('Method tests attachCallRecordInBase64 method')] + public function testAttachRecordInBase64(string $callId, int $currentB24UserId): void + { + $money = new Money(10000, new Currency('USD')); + $duration = 100; + $this->externalCall->finishForUserId( + $callId, + $currentB24UserId, + $duration, + $money, + TelephonyCallStatusCode::successful, + true + ); + $filename = dirname(__DIR__,2) . '/call-record-test.mp3'; + $this->assertGreaterThan(0, $this->externalCall->attachCallRecordInBase64( + $callId, + $filename + )->getRecordUploadedResult()->FILE_ID); + } + + #[Test] + #[DataProvider('callIdDataProvider')] + #[TestDox('Method tests getCallRecordUploadUrl method')] + public function testGetCallRecordUploadUrl(string $callId, int $currentB24UserId): void + { + $this->externalCall->finishForUserId( + $callId, + $currentB24UserId, + 100, + new Money(10000, new Currency('USD')), + TelephonyCallStatusCode::successful, + true + ); + + $filename = dirname(__DIR__,2) . '/call-record-test.mp3'; + $this->assertStringContainsString('https://', $this->externalCall->getCallRecordUploadUrl( + $callId, + $filename + )->getUploadUrlResult()->uploadUrl); + + } + + public function testSearchCrmEntities(): void + { + $searchCrmEntitiesResult = $this->externalCall->searchCrmEntities('79780000000'); + $this->assertGreaterThanOrEqual(0, count($searchCrmEntitiesResult->getCrmEntities())); + } + + protected function setUp(): void + { + $this->externalCall = Fabric::getServiceBuilder(true)->getTelephonyScope()->externalCall(); + $this->serviceBuilder = Fabric::getServiceBuilder(true); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php b/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php new file mode 100644 index 00000000..e89edda0 --- /dev/null +++ b/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\Telephony\ExternalLine\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\Telephony\ExternalLine\Service\ExternalLine; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; +use Random\RandomException; + +#[CoversClass(ExternalLine::class)] +#[CoversClass(ExternalLine::class)] +class ExternalLineTest extends TestCase +{ + private ExternalLine $externalLine; + + /** + * @throws TransportException + * @throws BaseException + * @throws RandomException + */ + #[Test] + #[TestDox('Method tests add external line method')] + public function testExternalLineAdd(): void + { + $lineNumber = time() . abs(random_int(PHP_INT_MIN, PHP_INT_MAX)); + $externalLineAddedResult = $this->externalLine->add($lineNumber, true, sprintf('line-name-%s', $lineNumber)); + $this->assertGreaterThan(0, $externalLineAddedResult->getExternalLineAddResultItem()->ID); + $this->assertContains($lineNumber, array_column($this->externalLine->get()->getExternalLines(), 'NUMBER')); + } + + #[Test] + #[TestDox('Method tests get external lines method')] + public function testGetExternalLine(): void + { + $externalLinesResult = $this->externalLine->get(); + $this->assertGreaterThan(1, count($externalLinesResult->getExternalLines())); + } + + /** + * @throws BaseException + * @throws TransportException + * @throws RandomException + */ + #[Test] + #[TestDox('Method tests delete external line method')] + public function testDeleteExternalLine(): void + { + $lineNumber = time() . abs(random_int(PHP_INT_MIN, PHP_INT_MAX)); + $this->externalLine->add($lineNumber, true, sprintf('line-name-%s', $lineNumber)); + + $this->assertContains($lineNumber, array_column($this->externalLine->get()->getExternalLines(), 'NUMBER')); + + $emptyResult = $this->externalLine->delete($lineNumber); + $this->assertEquals([], $emptyResult->getCoreResponse()->getResponseData()->getResult()); + + $this->assertNotContains($lineNumber, array_column($this->externalLine->get()->getExternalLines(), 'NUMBER')); + } + + protected function setUp(): void + { + $this->externalLine = Fabric::getServiceBuilder(true)->getTelephonyScope()->externalLine(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/Voximplant/InfoCall/Service/InfoCallTest.php b/tests/Integration/Services/Telephony/Voximplant/InfoCall/Service/InfoCallTest.php new file mode 100644 index 00000000..dd08922e --- /dev/null +++ b/tests/Integration/Services/Telephony/Voximplant/InfoCall/Service/InfoCallTest.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\Telephony\Voximplant\InfoCall\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\MethodConfirmWaitingException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\Telephony\Common\PbxType; +use Bitrix24\SDK\Services\Telephony\ExternalLine\Service\ExternalLine; +use Bitrix24\SDK\Services\Telephony\Voximplant\InfoCall\Service\InfoCall; +use Bitrix24\SDK\Services\Telephony\Voximplant\Line\Service\Line; +use Bitrix24\SDK\Services\Telephony\Voximplant\User\Service\User; +use Bitrix24\SDK\Tests\Builders\DemoDataGenerator; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[CoversClass(InfoCall::class)] +class InfoCallTest extends TestCase +{ + private InfoCall $infoCall; + + private Line $line; + + #[Test] + #[TestDox('Method tests voximplant info call with text')] + public function tesStartWithText(): void + { + $lines = $this->line->get()->getLines(); + if ($lines === []) { + $this->markTestSkipped('active lines not found - test start with text skipped'); + } + + $this->assertTrue($this->infoCall->startWithText( + $lines[0]->LINE_ID, + DemoDataGenerator::getMobilePhone()->getNationalNumber(), + 'test message' + )->getCallResult()->RESULT); + } + + #[Test] + #[TestDox('Method tests voximplant info call with sound')] + public function tesStartWithSound(): void + { + $lines = $this->line->get()->getLines(); + if ($lines === []) { + $this->markTestSkipped('active lines not found - test start with text skipped'); + } + + $this->assertTrue($this->infoCall->startWithSound( + $lines[0]->LINE_ID, + DemoDataGenerator::getMobilePhone()->getNationalNumber(), + DemoDataGenerator::getRecordFileUrl() + )->getCallResult()->RESULT); + } + + protected function setUp(): void + { + $this->infoCall = Fabric::getServiceBuilder(false)->getTelephonyScope()->getVoximplantServiceBuilder()->infoCall(); + $this->line = Fabric::getServiceBuilder(false)->getTelephonyScope()->getVoximplantServiceBuilder()->line(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/Voximplant/Line/Service/LineTest.php b/tests/Integration/Services/Telephony/Voximplant/Line/Service/LineTest.php new file mode 100644 index 00000000..d038867a --- /dev/null +++ b/tests/Integration/Services/Telephony/Voximplant/Line/Service/LineTest.php @@ -0,0 +1,86 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\Telephony\Voximplant\Line\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\MethodConfirmWaitingException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\Telephony\Common\PbxType; +use Bitrix24\SDK\Services\Telephony\ExternalLine\Service\ExternalLine; +use Bitrix24\SDK\Services\Telephony\Voximplant\InfoCall\Service\InfoCall; +use Bitrix24\SDK\Services\Telephony\Voximplant\Line\Service\Line; +use Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Service\Sip; +use Bitrix24\SDK\Services\Telephony\Voximplant\User\Service\User; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; +use Symfony\Component\Uid\Uuid; + +#[CoversClass(Line::class)] +class LineTest extends TestCase +{ + private Line $line; + + private Sip $sip; + + #[Test] + #[TestDox('Method tests returns list of all of the available outgoing lines')] + public function testOutgoingSipSet(): void + { + $sipTitle = 'test sip - ' . Uuid::v4()->toRfc4122(); + $serverUrl = 'supersip.io'; + $login = Uuid::v4()->toRfc4122(); + $password = Uuid::v4()->toRfc4122(); + + $sipLineAddedResult = $this->sip->add( + PbxType::cloud, + $sipTitle, + $serverUrl, + $login, + $password + ); + + $this->assertTrue($this->line->outgoingSipSet($sipLineAddedResult->getLine()->ID)->isSuccess()); + $this->sip->delete($sipLineAddedResult->getLine()->ID); + } + + #[Test] + #[TestDox('Method tests returns list of all of the available outgoing lines')] + public function testGet(): void + { + $this->assertGreaterThanOrEqual(0, count($this->line->get()->getLines())); + } + + #[Test] + #[TestDox('Method tests returns the currently selected line as an outgoing line by default.')] + public function testOutgoingGet(): void + { + $this->assertNotEmpty($this->line->outgoingGet()->getLineId()->LINE_ID); + } + + #[Test] + #[TestDox('Method sets the selected line as an outgoing line by default.')] + public function testOutgoingSet(): void + { + $this->assertTrue($this->line->outgoingSet('1')->isSuccess()); + } + + protected function setUp(): void + { + $this->line = Fabric::getServiceBuilder(false)->getTelephonyScope()->getVoximplantServiceBuilder()->line(); + $this->sip = Fabric::getServiceBuilder(false)->getTelephonyScope()->getVoximplantServiceBuilder()->sip(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/Voximplant/Sip/SipTest.php b/tests/Integration/Services/Telephony/Voximplant/Sip/SipTest.php new file mode 100644 index 00000000..ed790441 --- /dev/null +++ b/tests/Integration/Services/Telephony/Voximplant/Sip/SipTest.php @@ -0,0 +1,182 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\Telephony\Voximplant\Sip; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\Telephony\Common\PbxType; +use Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Service\Sip; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; +use Symfony\Component\Uid\Uuid; + +#[CoversClass(Sip::class)] +class SipTest extends TestCase +{ + private Sip $sip; + + #[Test] + #[TestDox('Method tests return current status of the SIP Connector')] + public function testGetConnectorStatus():void + { + $this->assertGreaterThanOrEqual(0, $this->sip->getConnectorStatus()->getStatus()->FREE_MINUTES); + } + + /** + * @throws TransportException + * @throws BaseException + */ + #[Test] + #[TestDox('Method tests sip get method')] + public function testGet(): void + { + $sipTitle = 'test sip - ' . Uuid::v4()->toRfc4122(); + $serverUrl = 'supersip.io'; + $login = Uuid::v4()->toRfc4122(); + $password = Uuid::v4()->toRfc4122(); + + $sipLineAddedResult = $this->sip->add( + PbxType::cloud, + $sipTitle, + $serverUrl, + $login, + $password + ); + $this->assertGreaterThanOrEqual(1, count($this->sip->get()->getLines())); + $this->assertTrue($this->sip->delete($sipLineAddedResult->getLine()->CONFIG_ID)->isSuccess()); + } + + #[Test] + #[TestDox('Method tests sip delete line method')] + public function testDelete(): void + { + $sipTitle = 'test sip - ' . Uuid::v4()->toRfc4122(); + $serverUrl = 'supersip.io'; + $login = Uuid::v4()->toRfc4122(); + $password = Uuid::v4()->toRfc4122(); + + $sipLineAddedResult = $this->sip->add( + PbxType::cloud, + $sipTitle, + $serverUrl, + $login, + $password + ); + $this->assertTrue(in_array($sipLineAddedResult->getLine()->CONFIG_ID, array_column($this->sip->get()->getLines(), 'CONFIG_ID'))); + + $this->assertTrue($this->sip->delete($sipLineAddedResult->getLine()->CONFIG_ID)->isSuccess()); + + $this->assertFalse(in_array($sipLineAddedResult->getLine()->CONFIG_ID, array_column($this->sip->get()->getLines(), 'CONFIG_ID'))); + } + + /** + * @throws TransportException + * @throws BaseException + */ + #[Test] + #[TestDox('Method tests sip add line method')] + public function testAdd(): void + { + $sipTitle = 'test sip - ' . Uuid::v4()->toRfc4122(); + $serverUrl = 'supersip.io'; + $login = Uuid::v4()->toRfc4122(); + $password = Uuid::v4()->toRfc4122(); + + $sipLineAddedResult = $this->sip->add( + PbxType::cloud, + $sipTitle, + $serverUrl, + $login, + $password + ); + $this->assertEquals($sipTitle, $sipLineAddedResult->getLine()->TITLE); + $this->assertEquals($serverUrl, $sipLineAddedResult->getLine()->SERVER); + $this->assertEquals($login, $sipLineAddedResult->getLine()->LOGIN); + $this->assertEquals($password, $sipLineAddedResult->getLine()->PASSWORD); + + $this->sip->delete($sipLineAddedResult->getLine()->CONFIG_ID)->isSuccess(); + } + + #[Test] + #[TestDox('Method tests sip update line method')] + public function testUpdate(): void + { + $sipTitle = 'test sip - ' . Uuid::v4()->toRfc4122(); + $serverUrl = 'supersip.io'; + $login = Uuid::v4()->toRfc4122(); + $password = Uuid::v4()->toRfc4122(); + + $sipLineAddedResult = $this->sip->add( + PbxType::cloud, + $sipTitle, + $serverUrl, + $login, + $password + ); + + $newTitle = 'test sip updated title - ' . Uuid::v4()->toRfc4122(); + $this->assertTrue($this->sip->update( + $sipLineAddedResult->getLine()->CONFIG_ID, + $sipLineAddedResult->getLine()->TYPE, + $newTitle + )->isSuccess()); + + + $this->sip->delete($sipLineAddedResult->getLine()->CONFIG_ID)->isSuccess(); + } + + #[Test] + #[TestDox('Method tests sip get line status method')] + public function testStatus(): void + { + $sipTitle = 'test sip - ' . Uuid::v4()->toRfc4122(); + $serverUrl = 'supersip.io'; + $login = Uuid::v4()->toRfc4122(); + $password = Uuid::v4()->toRfc4122(); + + $sipLineAddedResult = $this->sip->add( + PbxType::cloud, + $sipTitle, + $serverUrl, + $login, + $password + ); + + $sipLineStatusItemResult = $this->sip->status($sipLineAddedResult->getLine()->REG_ID)->getStatus(); + $this->assertEquals($sipLineAddedResult->getLine()->REG_ID, $sipLineStatusItemResult->REG_ID); + + $this->sip->delete($sipLineAddedResult->getLine()->CONFIG_ID); + } + + /** + * @throws TransportException + * @throws BaseException + */ + protected function tearDown(): void + { + //delete all cloud pbx + $lines = $this->sip->get()->getLines(); + foreach ($lines as $line) { + $this->sip->delete($line->CONFIG_ID); + } + } + + protected function setUp(): void + { + $this->sip = Fabric::getServiceBuilder()->getTelephonyScope()->getVoximplantServiceBuilder()->sip(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/Voximplant/TTS/Voices/Service/VoicesTest.php b/tests/Integration/Services/Telephony/Voximplant/TTS/Voices/Service/VoicesTest.php new file mode 100644 index 00000000..1d7a47de --- /dev/null +++ b/tests/Integration/Services/Telephony/Voximplant/TTS/Voices/Service/VoicesTest.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\Telephony\Voximplant\TTS\Voices\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\Telephony\Common\PbxType; +use Bitrix24\SDK\Services\Telephony\ExternalLine\Service\ExternalLine; +use Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Service\Sip; +use Bitrix24\SDK\Services\Telephony\Voximplant\TTS\Voices\Service\Voices; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; +use Symfony\Component\Uid\Uuid; + +#[CoversClass(Voices::class)] +class VoicesTest extends TestCase +{ + private Voices $voices; + + /** + * @throws TransportException + * @throws BaseException + */ + #[Test] + #[TestDox('test list available voices for generation of speech')] + public function testGet(): void + { + $voximplantVoicesResult = $this->voices->get(); + $this->assertGreaterThanOrEqual(1, count($voximplantVoicesResult->getVoices())); + } + + protected function setUp(): void + { + $this->voices = Fabric::getServiceBuilder()->getTelephonyScope()->getVoximplantServiceBuilder()->ttsVoices(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/Voximplant/Url/Service/UrlTest.php b/tests/Integration/Services/Telephony/Voximplant/Url/Service/UrlTest.php new file mode 100644 index 00000000..70271de7 --- /dev/null +++ b/tests/Integration/Services/Telephony/Voximplant/Url/Service/UrlTest.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\Telephony\Voximplant\Url\Service; + +use Bitrix24\SDK\Services\Telephony\Voximplant\Url\Service\Url; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Url::class)] +class UrlTest extends TestCase +{ + private Url $url; + + #[Test] + #[TestDox('Method tests returns a set of links for browsing telephony scope pages.')] + public function testDeactivatePhone(): void + { + $this->assertEquals( + parse_url($this->url->core->getApiClient()->getCredentials()->getDomainUrl(), PHP_URL_HOST), + parse_url($this->url->get()->getPages()->detail_statistics, PHP_URL_HOST), + ); + } + + protected function setUp(): void + { + $this->url = Fabric::getServiceBuilder(true)->getTelephonyScope()->getVoximplantServiceBuilder()->url(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/Voximplant/User/UserTest.php b/tests/Integration/Services/Telephony/Voximplant/User/UserTest.php new file mode 100644 index 00000000..2245f5cb --- /dev/null +++ b/tests/Integration/Services/Telephony/Voximplant/User/UserTest.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\Telephony\Voximplant\User; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\MethodConfirmWaitingException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\Telephony\Common\PbxType; +use Bitrix24\SDK\Services\Telephony\ExternalLine\Service\ExternalLine; +use Bitrix24\SDK\Services\Telephony\Voximplant\User\Service\User; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[CoversClass(User::class)] +class UserTest extends TestCase +{ + private User $user; + + #[Test] + #[TestDox('Method tests voximplant deactivate user phone')] + public function testDeactivatePhone(): void + { + if ($this->user->core->getApiClient()->getCredentials()->isWebhookContext()) { + $this->markTestSkipped('this method needs application context, now webhook context available'); + } + + $userId = Fabric::getServiceBuilder()->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()->ID; + $this->assertTrue($this->user->deactivatePhone($userId)->isSuccess()); + } + + #[Test] + #[TestDox('Method tests voximplant activate user phone')] + public function testActivatePhone(): void + { + if ($this->user->core->getApiClient()->getCredentials()->isWebhookContext()) { + $this->markTestSkipped('this method needs application context, now webhook context available'); + } + + $userId = Fabric::getServiceBuilder()->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()->ID; + $this->assertTrue($this->user->activatePhone($userId)->isSuccess()); + } + + /** + * @throws TransportException + * @throws BaseException + */ + #[Test] + #[TestDox('Method tests voximplant get user profile')] + public function testGet(): void + { + if ($this->user->core->getApiClient()->getCredentials()->isWebhookContext()) { + $this->markTestSkipped('this method needs application context, now webhook context available'); + } + + try { + $userId = Fabric::getServiceBuilder()->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()->ID; + $users = $this->user->get([$userId, 2, 3]); + $this->assertGreaterThanOrEqual(1, count($users->getUsers())); + } catch (MethodConfirmWaitingException) { + $this->markTestSkipped('api call method «voximplant.user.get» revoked, waiting confirm from portal administrator'); + } + } + + protected function setUp(): void + { + $this->user = Fabric::getServiceBuilder(true)->getTelephonyScope()->getVoximplantServiceBuilder()->user(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/call-record-test.mp3 b/tests/Integration/Services/Telephony/call-record-test.mp3 new file mode 100644 index 00000000..58cec686 Binary files /dev/null and b/tests/Integration/Services/Telephony/call-record-test.mp3 differ diff --git a/tests/Integration/Services/User/Service/UserTest.php b/tests/Integration/Services/User/Service/UserTest.php new file mode 100644 index 00000000..ea98df75 --- /dev/null +++ b/tests/Integration/Services/User/Service/UserTest.php @@ -0,0 +1,145 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\User\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\User\Result\UserItemResult; +use Bitrix24\SDK\Services\User\Service\User; +use Bitrix24\SDK\Services\UserConsent\Service\UserConsent; +use Bitrix24\SDK\Services\UserConsent\Service\UserConsentAgreement; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[CoversClass(User::class)] +class UserTest extends TestCase +{ + private User $userService; + + /** + * @throws BaseException + * @throws TransportException + */ + #[TestDox('test get users with filter')] + public function testUserSearch(): void + { + $usersResult = $this->userService->search([ + 'NAME' => 'test', + ]); + $this->assertGreaterThanOrEqual(1, $usersResult->getCoreResponse()->getResponseData()->getPagination()->getTotal()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + #[TestDox('test get users list with internal phone')] + public function testGetWithInternalPhone(): void + { + $this->assertGreaterThanOrEqual( + 1, + $this->userService->get(['ID' => 'ASC'], [ + '!UF_PHONE_INNER' => null + ], true)->getCoreResponse()->getResponseData()->getPagination()->getTotal() + ); + } + + #[TestDox('test get users list with default arguments')] + public function testGetWithDefaultArguments(): void + { + $this->assertGreaterThanOrEqual(1, $this->userService->get([], [], true)->getCoreResponse()->getResponseData()->getPagination()->getTotal()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + #[TestDox('test get users list')] + public function testGet(): void + { + $this->assertGreaterThanOrEqual( + 1, + $this->userService->get(['ID' => 'ASC'], [], true)->getCoreResponse()->getResponseData()->getPagination()->getTotal() + ); + } + + #[TestDox('test user typehints')] + public function testGetByIdTypehints(): void + { + $user = $this->userService->get(['ID' => 'ASC'], [], true)->getUsers()[0]; + $this->assertIsInt($user->ID); + } + + public function testUpdate(): void + { + $newUser = [ + 'NAME' => 'Test', + 'EMAIL' => sprintf('%s.test@test.com', time()), + 'EXTRANET' => 'N', + 'UF_DEPARTMENT' => [1] + ]; + $userId = $this->userService->add($newUser)->getId(); + $this->assertTrue($this->userService->update($userId, ['NAME' => 'Test2'])->isSuccess()); + $this->assertEquals( + 'Test2', + $this->userService->get(['ID' => 'ASC'], [ + 'ID' => $userId + ])->getUsers()[0]->NAME + ); + } + + /** + * @throws BaseException + * @throws TransportException + */ + #[TestDox('test add user')] + public function testAdd(): void + { + $newUser = [ + 'NAME' => 'Test', + 'EMAIL' => sprintf('%s.test@test.com', time()), + 'EXTRANET' => 'N', + 'UF_DEPARTMENT' => [1] + ]; + $userId = $this->userService->add($newUser)->getId(); + $this->assertGreaterThanOrEqual(1, $userId); + } + + /** + * @throws BaseException + * @throws TransportException + */ + #[TestDox('test get current user')] + public function testUserCurrent(): void + { + $this->assertInstanceOf(UserItemResult::class, $this->userService->current()->user()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + #[TestDox('test get user fields')] + public function testGetUserFields(): void + { + $this->assertIsArray($this->userService->fields()->getFieldsDescription()); + } + + protected function setUp(): void + { + $this->userService = Fabric::getServiceBuilder()->getUserScope()->user(); + } +} \ No newline at end of file diff --git a/tests/Integration/Services/UserConsent/Service/UserConsentAgreementTest.php b/tests/Integration/Services/UserConsent/Service/UserConsentAgreementTest.php new file mode 100644 index 00000000..bb4c93dd --- /dev/null +++ b/tests/Integration/Services/UserConsent/Service/UserConsentAgreementTest.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\UserConsent\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\UserConsent\Service\UserConsentAgreement; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +class UserConsentAgreementTest extends TestCase +{ + private UserConsentAgreement $userConsentAgreementService; + + /** + * @throws BaseException + * @throws TransportException + */ + #[TestDox('test get agreements list')] + public function testList(): void + { + $this->assertIsArray($this->userConsentAgreementService->list()->getAgreements()); + } + + /** + * @throws BaseException + * @throws TransportException + */ + #[TestDox('test get agreements list')] + public function testText(): void + { + // get agreement id + $agreements = $this->userConsentAgreementService->list()->getAgreements(); + // empty agreement list + if ($agreements === []) { + $this->assertTrue(true); + + return; + } + + $agreementId = $agreements[0]->ID; + $userConsentAgreementTextItemResult = $this->userConsentAgreementService->text($agreementId, [ + 'button_caption' => 'Button call to action title', + 'fields' => 'fields collection: email, phone', + ])->text(); + + $this->assertNotNull($userConsentAgreementTextItemResult->TEXT); + $this->assertNotNull($userConsentAgreementTextItemResult->LABEL); + } + + protected 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..e52cf207 --- /dev/null +++ b/tests/Integration/Services/UserConsent/Service/UserConsentTest.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Services\UserConsent\Service; + +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Exceptions\TransportException; +use Bitrix24\SDK\Services\UserConsent\Service\UserConsent; +use Bitrix24\SDK\Services\UserConsent\Service\UserConsentAgreement; +use Bitrix24\SDK\Tests\Integration\Fabric; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +class UserConsentTest extends TestCase +{ + private UserConsent $userConsentService; + + private UserConsentAgreement $userConsentAgreementService; + + /** + * @throws BaseException + * @throws TransportException + */ + #[TestDox('test get agreements list')] + public function testAdd(): void + { + // get agreement id + $agreements = $this->userConsentAgreementService->list()->getAgreements(); + // empty agreement list + if ($agreements === []) { + $this->assertTrue(true); + + return; + } + + $agreementId = $agreements[0]->ID; + $addedItemResult = $this->userConsentService->add( + [ + 'agreement_id' => $agreementId, + 'ip' => '127.0.0.1', + 'origin_id' => 'offline', + 'originator_id' => 'test@gmail.com', + ] + ); + $this->assertIsInt($addedItemResult->getId()); + } + + protected 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/Temp/OperatingTimingTest.php b/tests/Temp/OperatingTimingTest.php new file mode 100644 index 00000000..35f48267 --- /dev/null +++ b/tests/Temp/OperatingTimingTest.php @@ -0,0 +1,159 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Integration\Core; + +use Bitrix24\SDK\Core\Batch; +use Bitrix24\SDK\Services\CRM\Contact\Service\Contact; +use Bitrix24\SDK\Tests\Integration\Fabric; +use DateTime; +use PHPUnit\Framework\TestCase; +use RuntimeException; + +/** + * Class OperatingTimingTest + * + * @package Bitrix24\SDK\Tests\Integration\OperatingTimingTest + */ +class OperatingTimingTest extends TestCase +{ + protected Contact $contactService; + protected Batch $batch; + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + public function testOperatingTiming(): void + { + // Since the Rest module version 22.0.0 in the cloud version of Bitrix24 in all rest request responses in the time array with + // with additional information about the request execution time, an additional operating key has been added, which + // talks about the execution time of a request to a method by a specific application. Query execution time data + // the method is summed up. If the query execution time exceeds 480 seconds within the past 10 minutes + // this method is blocked for the application. However, all other methods continue to work. + // The operating_reset_at key returns the timestamp at which part of the limit for this method will be released. + + //example: + //911 |operating 74.438894271851 |cur_time 2023-04-15 16:56:46 |op_reset_at 1681567606 → 2023-04-15 14:06:46 + //912 |operating 74.438894271851 |cur_time 2023-04-15 16:56:46 |op_reset_at 1681567606 → 2023-04-15 14:06:46 + //913 |operating 74.438894271851 |cur_time 2023-04-15 16:56:47 |op_reset_at 1681567606 → 2023-04-15 14:06:46 + //... + //1509 |operating 104.5405356884 |cur_time 2023-04-15 16:57:21 |op_reset_at 1681567640 → 2023-04-15 14:07:20 + //1510 |operating 104.5405356884 |cur_time 2023-04-15 16:57:21 |op_reset_at 1681567640 → 2023-04-15 14:07:20 + + +// $contactsToUpdate = $this->getContactsUpdateCommand(15000); +// +// +// //todo count the number of contacts to update and count the number of contacts that were updated, if it doesn’t match, then we crash with an error + + +// $cnt = 0; +// foreach ($this->contactService->batch->update($contactsToUpdate) as $b24ContactId => $contactUpdateResult) { +// $cnt++; +// +// $debugOperatingLog = sprintf( +// 'cnt %s |id %s |operating %s |cur_time %s |op_reset_at %s → %s', +// $cnt, +// $b24ContactId, +// $contactUpdateResult->getResponseData()->getTime()->getOperating(), +// $contactUpdateResult->getResponseData()->getTime()->getDateFinish()->format('Y-m-d H:i:s'), +// $contactUpdateResult->getResponseData()->getTime()->getOperatingResetAt(), +// (new DateTime)->setTimestamp($contactUpdateResult->getResponseData()->getTime()->getOperatingResetAt())->format('Y-m-d H:i:s') +// ) . PHP_EOL; +// file_put_contents('operating.log', $debugOperatingLog); +// } +// +// $this->assertEquals( +// count($contactsToUpdate), +// $cnt, +// sprintf('updated contacts count %s not equal to expected %s cmd items', $cnt, count($contactsToUpdate)) +// ); + + // step 1 - throwing a correct exception, saying that the method failed because the method was blocked + // problems: - you can lose some data when updating, because We don’t know which contacts in the client code have been updated and which ones haven’t, or do we know? + // todo clarification, if possible, return in an exception the remainder of the data that has not yet been updated +//[2023-04-15T14:17:57.881428+00:00] integration-test.INFO: getResponseData.responseBody {"responseBody": +//{"result": +//{ +// "result":[], +// "result_error": +// { +// "592dcd1e-cd14-410f-bab5-76b3ede717dd": +// { +// "error":"OPERATION_TIME_LIMIT", +// "error_description":"Method is blocked due to operation time limit." +// } +// }, +// "result_total":[], +// "result_next":[], +// "result_time":[]}, +// "time":{ +// "start":1681568278.071253, +// "finish":1681568278.097257, +// "duration":0.02600383758544922, +// "processing":0.0005891323089599609, +// "date_start":"2023-04-15T17:17:58+03:00", +// "date_finish":"2023-04-15T17:17:58+03:00", +// "operating_reset_at":1681568878, +// "operating":0 +// } +//} +//} {"file":"/Users/mesilov/work/msk03-dev/loyalty/bitrix24-php-sdk/src/Core/Response/Response.php","line":92,"class":"Bitrix24\\SDK\\Core\\Response\\Response","function":"getResponseData","memory_usage":"36 MB"} +//[2023-04-15T14:17:57.881514+00:00] integration-test.DEBUG: handleApiLevelErrors.start [] {"file":"/Users/mesilov/work/msk03-dev/loyalty/bitrix24-php-sdk/src/Core/Response/Response.php","line":152,"class":"Bitrix24\\SDK\\Core\\Response\\Response","function":"handleApiLevelErrors","memory_usage":"36 MB"} +//[2023-04-15T14:17:57.881645+00:00] integration-test.DEBUG: handleApiLevelErrors.finish [] {"file":"/Users/mesilov/work/msk03-dev/loyalty/bitrix24-php-sdk/src/Core/Response/Response.php","line":190,"class":"Bitrix24\\SDK\\Core\\Response\\Response","function":"handleApiLevelErrors","memory_usage":"36 MB"} +//[2023-04-15T14:17:57.881795+00:00] integration-test.DEBUG: getResponseData.parseResponse.finish [] +//[2023-04-15T14:37:47.371152+00:00] integration-test.INFO: getResponseData.responseBody {"responseBody":{"result":{"result":[],"result_error":{"f26b4ebc-3a82-4fe6-8d26-595d6eaf029b":{"error":"OPERATION_TIME_LIMIT","error_description":"Method is blocked due to operation time limit."}},"result_total":[],"result_next":[],"result_time":[]},"time":{"start":1681569467.49515,"finish":1681569467.519364,"duration":0.02421402931213379,"processing":0.0005979537963867188,"date_start":"2023-04-15T17:37:47+03:00","date_finish":"2023-04-15T17:37:47+03:00","operating_reset_at":1681570067,"operating":0}}} {"file":"/Users/mesilov/work/msk03-dev/loyalty/bitrix24-php-sdk/src/Core/Response/Response.php","line":92,"class":"Bitrix24\\SDK\\Core\\Response\\Response","function":"getResponseData","memory_usage":"36 MB"} +//[2023-04-15T14:37:47.371279+00:00] integration-test.DEBUG: handleApiLevelErrors.start [] {"file":"/Users/mesilov/work/msk03-dev/loyalty/bitrix24-php-sdk/src/Core/Response/Response.php","line":152,"class":"Bitrix24\\SDK\\Core\\Response\\Response","function":"handleApiLevelErrors","memory_usage":"36 MB"} + + + // step 2 - make separate strategies with logic for the batch and figure out how it could be + // - 2.1 waiting for the method to be unlocked without completing the batch, i.e. the script will hang for 10 minutes, then try to continue working, this can only be done if you are aware of the consequences + // - 2.2 event release \ handler call N seconds before the method is blocked, i.e. we delegate the processing logic to the client code + + } + + /** + * Get contacts for update command + * + * @param int $contactsToUpdateCount + * @return array + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + */ + private function getContactsUpdateCommand(int $contactsToUpdateCount): array + { + $filter = ['>ID' => '1']; + + $contactsCount = $this->contactService->countByFilter($filter); + if ($contactsCount < $contactsToUpdateCount) { + throw new RuntimeException(sprintf('Not enough contacts for test. Need %s, but have %s', $contactsToUpdateCount, $contactsCount)); + } + + $contactsToUpdate = []; + foreach ($this->contactService->batch->list([], $filter, ['ID', 'COMMENTS'], $contactsToUpdateCount) as $b24Contact) { + $contactsToUpdate[$b24Contact->ID] = [ + 'fields' => [ + 'COMMENTS' => $b24Contact->COMMENTS . time() . PHP_EOL, + ], + 'params' => [], + ]; + } + return $contactsToUpdate; + } + + public function setUp(): void + { + $this->batch = Fabric::getBatchService(); + $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); + } +} \ 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..b83a60e9 --- /dev/null +++ b/tests/Unit/Application/ApplicationStatusTest.php @@ -0,0 +1,109 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Application; + +use Bitrix24\SDK\Application\ApplicationStatus; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Generator; +use PHPUnit\Framework\TestCase; + +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Application\ApplicationStatus::class)] +class ApplicationStatusTest extends TestCase +{ + /** + * + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + #[\PHPUnit\Framework\Attributes\DataProvider('statusDataProvider')] + public function testGetStatusCode(string $shortCode, string $longCode): void + { + $this->assertEquals( + $longCode, + (new ApplicationStatus($shortCode))->getStatusCode() + ); + } + + public function testInvalidStatusCode(): void + { + $this->expectException(InvalidArgumentException::class); + new ApplicationStatus('foo'); + } + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public function testInitFromString(): void + { + $this->assertTrue(ApplicationStatus::initFromString('F')->isFree()); + } + + public function testFree(): void + { + $this->assertTrue(ApplicationStatus::free()->isFree()); + } + + public function testDemo(): void + { + $this->assertTrue(ApplicationStatus::demo()->isDemo()); + } + + public function testTrial(): void + { + $this->assertTrue(ApplicationStatus::trial()->isTrial()); + } + + public function testPaid(): void + { + $this->assertTrue(ApplicationStatus::paid()->isPaid()); + } + + public function testLocal(): void + { + $this->assertTrue(ApplicationStatus::local()->isLocal()); + } + + public function testSubscription(): void + { + $this->assertTrue(ApplicationStatus::subscription()->isSubscription()); + } + + public static 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/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceReferenceImplementationTest.php b/tests/Unit/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceReferenceImplementationTest.php new file mode 100644 index 00000000..044ae6ee --- /dev/null +++ b/tests/Unit/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceReferenceImplementationTest.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Application\Contracts\ApplicationInstallations\Entity; + +use Bitrix24\SDK\Application\ApplicationStatus; +use Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Entity\ApplicationInstallationInterface; +use Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Entity\ApplicationInstallationStatus; +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountInterface; +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountStatus; +use Bitrix24\SDK\Application\PortalLicenseFamily; +use Bitrix24\SDK\Core\Credentials\AuthToken; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Tests\Application\Contracts\ApplicationInstallations\Entity\ApplicationInstallationInterfaceTest; +use Bitrix24\SDK\Tests\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountInterfaceTest; +use Bitrix24\SDK\Tests\Unit\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountReferenceEntityImplementation; +use Carbon\CarbonImmutable; +use PHPUnit\Framework\Attributes\CoversClass; +use Symfony\Component\Uid\Uuid; + +#[CoversClass(Bitrix24AccountInterface::class)] +class ApplicationInstallationInterfaceReferenceImplementationTest extends ApplicationInstallationInterfaceTest +{ + protected function createApplicationInstallationImplementation( + Uuid $uuid, + ApplicationInstallationStatus $applicationInstallationStatus, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Uuid $bitrix24AccountUuid, + ApplicationStatus $applicationStatus, + PortalLicenseFamily $portalLicenseFamily, + ?int $portalUsersCount, + ?Uuid $clientContactPersonUuid, + ?Uuid $partnerContactPersonUuid, + ?Uuid $partnerUuid, + ?string $externalId, + ): ApplicationInstallationInterface + { + return new ApplicationInstallationReferenceEntityImplementation( + $uuid, + $applicationInstallationStatus, + $createdAt, + $updatedAt, + $bitrix24AccountUuid, + $applicationStatus, + $portalLicenseFamily, + $portalUsersCount, + $clientContactPersonUuid, + $partnerContactPersonUuid, + $partnerUuid, + $externalId, + ); + } +} \ No newline at end of file diff --git a/tests/Unit/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationReferenceEntityImplementation.php b/tests/Unit/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationReferenceEntityImplementation.php new file mode 100644 index 00000000..9245e287 --- /dev/null +++ b/tests/Unit/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationReferenceEntityImplementation.php @@ -0,0 +1,223 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Application\Contracts\ApplicationInstallations\Entity; + +use Bitrix24\SDK\Application\ApplicationStatus; +use Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Entity\ApplicationInstallationInterface; +use Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Entity\ApplicationInstallationStatus; +use Bitrix24\SDK\Application\PortalLicenseFamily; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; + +/** + * Class ApplicationInstallationReferenceEntityImplementation + * + * This class uses ONLY for demonstration and tests interface, use cases for work with ApplicationInstallationInterface methods + * + */ +final class ApplicationInstallationReferenceEntityImplementation implements ApplicationInstallationInterface +{ + private ?string $comment = null; + + public function __construct( + private readonly Uuid $id, + private ApplicationInstallationStatus $applicationInstallationStatus, + private readonly CarbonImmutable $createdAt, + private CarbonImmutable $updatedAt, + private readonly Uuid $bitrix24AccountUuid, + private ApplicationStatus $applicationStatus, + private PortalLicenseFamily $portalLicenseFamily, + private ?int $portalUsersCount, + private ?Uuid $clientContactPersonUuid, + private ?Uuid $partnerContactPersonUuid, + private ?Uuid $bitrix24PartnerUuid, + private ?string $externalId, + ) + { + } + + public function getId(): Uuid + { + return $this->id; + } + + public function getCreatedAt(): CarbonImmutable + { + return $this->createdAt; + } + + public function getUpdatedAt(): CarbonImmutable + { + return $this->updatedAt; + } + + public function getStatus(): ApplicationInstallationStatus + { + return $this->applicationInstallationStatus; + } + + public function getBitrix24AccountId(): Uuid + { + return $this->bitrix24AccountUuid; + } + + public function getApplicationStatus(): ApplicationStatus + { + return $this->applicationStatus; + } + + public function getPortalLicenseFamily(): PortalLicenseFamily + { + return $this->portalLicenseFamily; + } + + public function changePortalLicenseFamily(PortalLicenseFamily $portalLicenseFamily): void + { + $this->portalLicenseFamily = $portalLicenseFamily; + $this->updatedAt = new CarbonImmutable(); + } + + public function getPortalUsersCount(): ?int + { + return $this->portalUsersCount; + } + + public function changePortalUsersCount(int $usersCount): void + { + $this->portalUsersCount = $usersCount; + $this->updatedAt = new CarbonImmutable(); + } + + public function getContactPersonId(): ?Uuid + { + return $this->clientContactPersonUuid; + } + + public function changeContactPerson(?Uuid $uuid): void + { + $this->clientContactPersonUuid = $uuid; + $this->updatedAt = new CarbonImmutable(); + } + + public function getBitrix24PartnerContactPersonId(): ?Uuid + { + return $this->partnerContactPersonUuid; + } + + public function changeBitrix24PartnerContactPerson(?Uuid $uuid): void + { + $this->partnerContactPersonUuid = $uuid; + $this->updatedAt = new CarbonImmutable(); + } + + public function getBitrix24PartnerId(): ?Uuid + { + return $this->bitrix24PartnerUuid; + } + + public function changeBitrix24Partner(?Uuid $uuid): void + { + $this->bitrix24PartnerUuid = $uuid; + $this->updatedAt = new CarbonImmutable(); + } + + public function getExternalId(): ?string + { + return $this->externalId; + } + + public function setExternalId(?string $externalId): void + { + if (($externalId !== null) && trim($externalId) === '') { + throw new InvalidArgumentException('externalId cannot be empty string'); + } + + $this->externalId = $externalId; + $this->updatedAt = new CarbonImmutable(); + } + + /** + * @throws InvalidArgumentException + */ + public function applicationInstalled(): void + { + if ($this->applicationInstallationStatus !== ApplicationInstallationStatus::new) { + throw new InvalidArgumentException(sprintf('application installation must be in status «%s», current state «%s»', + ApplicationInstallationStatus::new->name, + $this->applicationInstallationStatus->name + )); + } + + $this->applicationInstallationStatus = ApplicationInstallationStatus::active; + $this->updatedAt = new CarbonImmutable(); + } + + /** + * @throws InvalidArgumentException + */ + public function applicationUninstalled(): void + { + if ($this->applicationInstallationStatus === ApplicationInstallationStatus::new || $this->applicationInstallationStatus === ApplicationInstallationStatus::deleted) { + throw new InvalidArgumentException(sprintf('application installation must be in status «%s» or «%s», current state «%s»', + ApplicationInstallationStatus::active->name, + ApplicationInstallationStatus::blocked->name, + $this->applicationInstallationStatus->name + )); + } + + $this->applicationInstallationStatus = ApplicationInstallationStatus::deleted; + $this->updatedAt = new CarbonImmutable(); + } + + public function markAsActive(?string $comment): void + { + if ($this->applicationInstallationStatus !== ApplicationInstallationStatus::blocked) { + throw new InvalidArgumentException(sprintf('you can activate application install only in state «%s», current state «%s»', + ApplicationInstallationStatus::blocked->name, + $this->applicationInstallationStatus->name + )); + } + + $this->applicationInstallationStatus = ApplicationInstallationStatus::active; + $this->comment = $comment; + $this->updatedAt = new CarbonImmutable(); + } + + public function markAsBlocked(?string $comment): void + { + if ($this->applicationInstallationStatus === ApplicationInstallationStatus::blocked || $this->applicationInstallationStatus === ApplicationInstallationStatus::deleted) { + throw new InvalidArgumentException(sprintf('you can block application install only in state «%s» or «%s», current state «%s»', + ApplicationInstallationStatus::new->name, + ApplicationInstallationStatus::active->name, + $this->applicationInstallationStatus->name + )); + } + + $this->applicationInstallationStatus = ApplicationInstallationStatus::blocked; + $this->comment = $comment; + $this->updatedAt = new CarbonImmutable(); + } + + public function changeApplicationStatus(ApplicationStatus $applicationStatus): void + { + $this->applicationStatus = $applicationStatus; + $this->updatedAt = new CarbonImmutable(); + } + + public function getComment(): ?string + { + return $this->comment; + } +} diff --git a/tests/Unit/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementation.php b/tests/Unit/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementation.php new file mode 100644 index 00000000..112fa944 --- /dev/null +++ b/tests/Unit/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementation.php @@ -0,0 +1,100 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Application\Contracts\ApplicationInstallations\Repository; + +use Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Entity\ApplicationInstallationInterface; +use Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Entity\ApplicationInstallationStatus; +use Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Exceptions\ApplicationInstallationNotFoundException; +use Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Repository\ApplicationInstallationRepositoryInterface; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Psr\Log\LoggerInterface; +use Symfony\Component\Uid\Uuid; + +class InMemoryApplicationInstallationRepositoryImplementation implements ApplicationInstallationRepositoryInterface +{ + /** + * @var ApplicationInstallationInterface[] + */ + private array $items = []; + + public function __construct( + private readonly LoggerInterface $logger + ) + { + } + + public function save(ApplicationInstallationInterface $applicationInstallation): void + { + $this->logger->debug('InMemoryApplicationInstallationRepositoryImplementation.save', ['id' => $applicationInstallation->getId()->toRfc4122()]); + + $this->items[$applicationInstallation->getId()->toRfc4122()] = $applicationInstallation; + } + + public function delete(Uuid $uuid): void + { + $this->logger->debug('InMemoryApplicationInstallationRepositoryImplementation.delete', ['id' => $uuid->toRfc4122()]); + + $applicationInstallation = $this->getById($uuid); + if (ApplicationInstallationStatus::deleted !== $applicationInstallation->getStatus()) { + throw new InvalidArgumentException(sprintf('you cannot delete application installation «%s», in status «%s», mark applicatoin installation as «deleted» before', + $applicationInstallation->getId()->toRfc4122(), + $applicationInstallation->getStatus()->name, + )); + } + + unset($this->items[$uuid->toRfc4122()]); + } + + public function getById(Uuid $uuid): ApplicationInstallationInterface + { + $this->logger->debug('InMemoryApplicationInstallationRepositoryImplementation.getById', ['id' => $uuid->toRfc4122()]); + + if (!array_key_exists($uuid->toRfc4122(), $this->items)) { + throw new ApplicationInstallationNotFoundException(sprintf('application installation not found by id «%s» ', $uuid->toRfc4122())); + } + + return $this->items[$uuid->toRfc4122()]; + } + + public function findByBitrix24AccountId(Uuid $uuid): array + { + $this->logger->debug('InMemoryApplicationInstallationRepositoryImplementation.findByBitrix24AccountId', ['id' => $uuid->toRfc4122()]); + + $result = []; + foreach ($this->items as $item) { + if ($item->getBitrix24AccountId() === $uuid) { + $result[] = $item; + } + } + + return $result; + } + + public function findByExternalId(string $externalId): array + { + $this->logger->debug('InMemoryApplicationInstallationRepositoryImplementation.findByExternalId', ['externalId' => $externalId]); + if (trim($externalId) === '') { + throw new InvalidArgumentException('external id cannot be empty string'); + } + + $result = []; + foreach ($this->items as $item) { + if ($item->getExternalId() === $externalId) { + $result[] = $item; + } + } + + return $result; + } +} \ No newline at end of file diff --git a/tests/Unit/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementationTest.php b/tests/Unit/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementationTest.php new file mode 100644 index 00000000..45a8bd8d --- /dev/null +++ b/tests/Unit/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementationTest.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Application\Contracts\ApplicationInstallations\Repository; + +use Bitrix24\SDK\Application\ApplicationStatus; +use Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Entity\ApplicationInstallationInterface; +use Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Entity\ApplicationInstallationStatus; +use Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Repository\ApplicationInstallationRepositoryInterface; +use Bitrix24\SDK\Application\PortalLicenseFamily; +use Bitrix24\SDK\Tests\Application\Contracts\ApplicationInstallations\Repository\ApplicationInstallationRepositoryInterfaceTest; +use Bitrix24\SDK\Tests\Integration\Fabric; +use Bitrix24\SDK\Tests\Unit\Application\Contracts\ApplicationInstallations\Entity\ApplicationInstallationReferenceEntityImplementation; +use Carbon\CarbonImmutable; +use PHPUnit\Framework\Attributes\CoversClass; +use Psr\Log\NullLogger; +use Symfony\Component\Uid\Uuid; + +#[CoversClass(ApplicationInstallationRepositoryInterface::class)] +class InMemoryApplicationInstallationRepositoryImplementationTest extends ApplicationInstallationRepositoryInterfaceTest +{ + protected function createApplicationInstallationImplementation(Uuid $uuid, ApplicationInstallationStatus $applicationInstallationStatus, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, Uuid $bitrix24AccountUuid, ApplicationStatus $applicationStatus, PortalLicenseFamily $portalLicenseFamily, ?int $portalUsersCount, ?Uuid $clientContactPersonUuid, ?Uuid $partnerContactPersonUuid, ?Uuid $partnerUuid, ?string $externalId,): ApplicationInstallationInterface + { + return new ApplicationInstallationReferenceEntityImplementation( + $uuid, + $applicationInstallationStatus, + $createdAt, + $updatedAt, + $bitrix24AccountUuid, + $applicationStatus, + $portalLicenseFamily, + $portalUsersCount, + $clientContactPersonUuid, + $partnerContactPersonUuid, + $partnerUuid, + $externalId, + ); + } + + protected function createApplicationInstallationRepositoryImplementation(): ApplicationInstallationRepositoryInterface + { + return new InMemoryApplicationInstallationRepositoryImplementation(new NullLogger()); + } +} \ No newline at end of file diff --git a/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceReferenceImplementationTest.php b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceReferenceImplementationTest.php new file mode 100644 index 00000000..a6fa96be --- /dev/null +++ b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceReferenceImplementationTest.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Application\Contracts\Bitrix24Accounts\Entity; + +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountInterface; +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountStatus; +use Bitrix24\SDK\Core\Credentials\AuthToken; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Tests\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountInterfaceTest; +use Carbon\CarbonImmutable; +use PHPUnit\Framework\Attributes\CoversClass; +use Symfony\Component\Uid\Uuid; + +#[CoversClass(Bitrix24AccountInterface::class)] +class +Bitrix24AccountInterfaceReferenceImplementationTest extends Bitrix24AccountInterfaceTest +{ + protected function createBitrix24AccountImplementation( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): Bitrix24AccountInterface + { + return new Bitrix24AccountReferenceEntityImplementation( + $uuid, + $bitrix24UserId, + $isBitrix24UserAdmin, + $memberId, + $domainUrl, + $bitrix24AccountStatus, + $authToken, + $createdAt, + $updatedAt, + $applicationVersion, + $applicationScope + ); + } +} \ No newline at end of file diff --git a/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountReferenceEntityImplementation.php b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountReferenceEntityImplementation.php new file mode 100644 index 00000000..e441c11d --- /dev/null +++ b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountReferenceEntityImplementation.php @@ -0,0 +1,285 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Application\Contracts\Bitrix24Accounts\Entity; + +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountInterface; +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountStatus; +use Bitrix24\SDK\Core\Credentials\AuthToken; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException; +use Bitrix24\SDK\Core\Response\DTO\RenewedAuthToken; +use Carbon\CarbonImmutable; +use Symfony\Component\Uid\Uuid; + +/** + * Class Bitrix24AccountReferenceEntityImplementation + * + * This class uses ONLY for demonstration and tests interface, use cases for work with Bitrix24AccountInterface methods + * + */ +final class Bitrix24AccountReferenceEntityImplementation implements Bitrix24AccountInterface +{ + private string $accessToken; + + private string $refreshToken; + + private int $expires; + + private array $applicationScope; + + private ?string $applicationToken = null; + + private ?string $comment = null; + + public function __construct( + private readonly Uuid $id, + private readonly int $bitrix24UserId, + private readonly bool $isBitrix24UserAdmin, + private readonly string $memberId, + private string $domainUrl, + private Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + private readonly CarbonImmutable $createdAt, + private CarbonImmutable $updatedAt, + private int $applicationVersion, + Scope $applicationScope, + ) + { + $this->accessToken = $authToken->getAccessToken(); + $this->refreshToken = $authToken->getRefreshToken(); + $this->expires = $authToken->getExpires(); + $this->applicationScope = $applicationScope->getScopeCodes(); + } + + public function getId(): Uuid + { + return $this->id; + } + + public function getBitrix24UserId(): int + { + return $this->bitrix24UserId; + } + + public function isBitrix24UserAdmin(): bool + { + return $this->isBitrix24UserAdmin; + } + + public function getMemberId(): string + { + return $this->memberId; + } + + public function getDomainUrl(): string + { + return $this->domainUrl; + } + + public function getStatus(): Bitrix24AccountStatus + { + return $this->accountStatus; + } + + public function getAuthToken(): AuthToken + { + return new AuthToken($this->accessToken, $this->refreshToken, $this->expires); + } + + /** + * @throws InvalidArgumentException + */ + public function renewAuthToken(RenewedAuthToken $renewedAuthToken): void + { + if ($this->memberId !== $renewedAuthToken->memberId) { + throw new InvalidArgumentException( + sprintf( + 'member id %s for bitrix24 account %s for domain %s mismatch with member id %s for renewed access token', + $this->memberId, + $this->id->toRfc4122(), + $this->domainUrl, + $renewedAuthToken->memberId, + ) + ); + } + + $this->accessToken = $renewedAuthToken->authToken->getAccessToken(); + $this->refreshToken = $renewedAuthToken->authToken->getRefreshToken(); + $this->expires = $renewedAuthToken->authToken->getExpires(); + $this->updatedAt = new CarbonImmutable(); + } + + public function getApplicationVersion(): int + { + return $this->applicationVersion; + } + + /** + * @throws UnknownScopeCodeException + */ + public function getApplicationScope(): Scope + { + return new Scope($this->applicationScope); + } + + /** + * @throws InvalidArgumentException + */ + public function changeDomainUrl(string $newDomainUrl): void + { + if ($newDomainUrl === '') { + throw new InvalidArgumentException('new domain url cannot be empty'); + } + + if (Bitrix24AccountStatus::blocked === $this->accountStatus || Bitrix24AccountStatus::deleted === $this->accountStatus) { + throw new InvalidArgumentException( + sprintf( + 'bitrix24 account %s for domain %s must be in active or new state, now account in %s state. domain url cannot be changed', + $this->id->toRfc4122(), + $this->domainUrl, + $this->accountStatus->name + ) + ); + } + + $this->domainUrl = $newDomainUrl; + $this->updatedAt = new CarbonImmutable(); + } + + /** + * @throws InvalidArgumentException + */ + public function applicationInstalled(string $applicationToken): void + { + if (Bitrix24AccountStatus::new !== $this->accountStatus) { + throw new InvalidArgumentException(sprintf( + 'for finish installation bitrix24 account must be in status «new», current status - «%s»', + $this->accountStatus->name)); + } + + if ($applicationToken === '') { + throw new InvalidArgumentException('application token cannot be empty'); + } + + $this->accountStatus = Bitrix24AccountStatus::active; + $this->applicationToken = $applicationToken; + $this->updatedAt = new CarbonImmutable(); + } + + /** + * @throws InvalidArgumentException + */ + public function applicationUninstalled(string $applicationToken): void + { + if ($applicationToken === '') { + throw new InvalidArgumentException('application token cannot be empty'); + } + + if (Bitrix24AccountStatus::active !== $this->accountStatus) { + throw new InvalidArgumentException(sprintf( + 'for uninstall account must be in status «active», current status - «%s»', + $this->accountStatus->name)); + } + + if ($this->applicationToken !== $applicationToken) { + throw new InvalidArgumentException( + sprintf( + 'application token «%s» mismatch with application token «%s» for bitrix24 account %s for domain %s', + $applicationToken, + $this->applicationToken, + $this->id->toRfc4122(), + $this->domainUrl + ) + ); + } + + $this->accountStatus = Bitrix24AccountStatus::deleted; + $this->updatedAt = new CarbonImmutable(); + } + + public function isApplicationTokenValid(string $applicationToken): bool + { + return $this->applicationToken === $applicationToken; + } + + public function getCreatedAt(): CarbonImmutable + { + return $this->createdAt; + } + + public function getUpdatedAt(): CarbonImmutable + { + return $this->updatedAt; + } + + /** + * @throws InvalidArgumentException + */ + public function updateApplicationVersion(int $version, ?Scope $newScope): void + { + if (Bitrix24AccountStatus::active !== $this->accountStatus) { + throw new InvalidArgumentException(sprintf('account must be in status «active», but now account in status «%s»', $this->accountStatus->name)); + } + + if ($this->applicationVersion >= $version) { + throw new InvalidArgumentException( + sprintf('you cannot downgrade application version or set some version, current version «%s», but you try to upgrade to «%s»', + $this->applicationVersion, + $version)); + } + + $this->applicationVersion = $version; + if ($newScope instanceof \Bitrix24\SDK\Core\Credentials\Scope) { + $this->applicationScope = $newScope->getScopeCodes(); + } + + $this->updatedAt = new CarbonImmutable(); + } + + /** + * @throws InvalidArgumentException + */ + public function markAsActive(?string $comment): void + { + if (Bitrix24AccountStatus::blocked !== $this->accountStatus) { + throw new InvalidArgumentException( + sprintf('you can activate account only in status blocked, now account in status %s', + $this->accountStatus->name)); + } + + $this->accountStatus = Bitrix24AccountStatus::active; + $this->comment = $comment; + $this->updatedAt = new CarbonImmutable(); + } + + /** + * @throws InvalidArgumentException + */ + public function markAsBlocked(?string $comment): void + { + if (Bitrix24AccountStatus::deleted === $this->accountStatus) { + throw new InvalidArgumentException('you cannot block account in status «deleted»'); + } + + $this->accountStatus = Bitrix24AccountStatus::blocked; + $this->comment = $comment; + $this->updatedAt = new CarbonImmutable(); + } + + public function getComment(): ?string + { + return $this->comment; + } +} diff --git a/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementation.php b/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementation.php new file mode 100644 index 00000000..b8a3ab66 --- /dev/null +++ b/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementation.php @@ -0,0 +1,156 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Application\Contracts\Bitrix24Accounts\Repository; + + +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountInterface; +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountStatus; +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Exceptions\Bitrix24AccountNotFoundException; +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Repository\Bitrix24AccountRepositoryInterface; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Psr\Log\LoggerInterface; +use Symfony\Component\Uid\Uuid; + +class InMemoryBitrix24AccountRepositoryImplementation implements Bitrix24AccountRepositoryInterface +{ + /** + * @var Bitrix24AccountInterface[] + */ + private array $items = []; + + public function __construct( + private readonly LoggerInterface $logger + ) + { + } + + public function save(Bitrix24AccountInterface $bitrix24Account): void + { + $this->logger->debug('b24AccountRepository.save', ['id' => $bitrix24Account->getId()->toRfc4122()]); + + $this->items[$bitrix24Account->getId()->toRfc4122()] = $bitrix24Account; + } + + public function delete(Uuid $uuid): void + { + $this->logger->debug('b24AccountRepository.delete', ['id' => $uuid->toRfc4122()]); + + $bitrix24Account = $this->getById($uuid); + if (Bitrix24AccountStatus::deleted !== $bitrix24Account->getStatus()) { + throw new InvalidArgumentException(sprintf('you cannot delete bitrix24account «%s», they must be in status deleted, current status «%s»', + $bitrix24Account->getId()->toRfc4122(), + $bitrix24Account->getStatus()->name + )); + } + + unset($this->items[$uuid->toRfc4122()]); + } + + public function getById(Uuid $uuid): Bitrix24AccountInterface + { + $this->logger->debug('b24AccountRepository.getById', ['id' => $uuid->toRfc4122()]); + + if (!array_key_exists($uuid->toRfc4122(), $this->items)) { + throw new Bitrix24AccountNotFoundException(sprintf('bitrix24 account not found for id «%s» ', $uuid->toRfc4122())); + } + + return $this->items[$uuid->toRfc4122()]; + } + + /** + * @throws InvalidArgumentException + */ + public function findOneAdminByMemberId(string $memberId): ?Bitrix24AccountInterface + { + $this->logger->debug('b24AccountRepository.findOneAdminByMemberId', ['memberId' => $memberId]); + + if ($memberId === '') { + throw new InvalidArgumentException('memberId cannot be empty'); + } + + foreach ($this->items as $item) { + if ($item->getMemberId() === $memberId && $item->isBitrix24UserAdmin()) { + return $item; + } + } + + return null; + } + + /** + * @throws InvalidArgumentException + */ + public function findByMemberId(string $memberId, ?Bitrix24AccountStatus $bitrix24AccountStatus = null, ?bool $isAdmin = null): array + { + $this->logger->debug('b24AccountRepository.findByMemberId', [ + 'memberId' => $memberId, + 'status' => $bitrix24AccountStatus?->name, + 'isAdmin' => $isAdmin + ]); + + if ($memberId === '') { + throw new InvalidArgumentException('memberId cannot be empty'); + } + + $items = []; + foreach ($this->items as $item) { + if ($item->getMemberId() !== $memberId) { + continue; + } + + $isStatusMatch = (!$bitrix24AccountStatus instanceof Bitrix24AccountStatus || $bitrix24AccountStatus === $item->getStatus()); + $isAdminMatch = ($isAdmin === null || $isAdmin === $item->isBitrix24UserAdmin()); + + if ($isStatusMatch && $isAdminMatch) { + $items[] = $item; + } + + } + + return $items; + } + + /** + * @throws InvalidArgumentException + */ + public function findByDomain(string $domainUrl, ?Bitrix24AccountStatus $bitrix24AccountStatus = null, ?bool $isAdmin = null): array + { + $this->logger->debug('b24AccountRepository.findByDomain', [ + 'domain' => $domainUrl, + 'status' => $bitrix24AccountStatus?->name, + 'isAdmin' => $isAdmin + ]); + + if ($domainUrl === '') { + throw new InvalidArgumentException('domain url cannot be empty'); + } + + $items = []; + foreach ($this->items as $item) { + if ($item->getDomainUrl() !== $domainUrl) { + continue; + } + + $isStatusMatch = (!$bitrix24AccountStatus instanceof Bitrix24AccountStatus || $bitrix24AccountStatus === $item->getStatus()); + $isAdminMatch = ($isAdmin === null || $isAdmin === $item->isBitrix24UserAdmin()); + + if ($isStatusMatch && $isAdminMatch) { + $items[] = $item; + } + + } + + return $items; + } +} \ No newline at end of file diff --git a/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementationTest.php b/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementationTest.php new file mode 100644 index 00000000..689a6a54 --- /dev/null +++ b/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementationTest.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Application\Contracts\Bitrix24Accounts\Repository; + +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountInterface; +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountStatus; +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Repository\Bitrix24AccountRepositoryInterface; +use Bitrix24\SDK\Core\Credentials\AuthToken; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Tests\Application\Contracts\Bitrix24Accounts\Repository\Bitrix24AccountRepositoryInterfaceTest; +use Bitrix24\SDK\Tests\Integration\Fabric; +use Bitrix24\SDK\Tests\Unit\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountReferenceEntityImplementation; +use Carbon\CarbonImmutable; +use PHPUnit\Framework\Attributes\CoversClass; +use Psr\Log\NullLogger; +use Symfony\Component\Uid\Uuid; + +#[CoversClass(Bitrix24AccountRepositoryInterface::class)] +class InMemoryBitrix24AccountRepositoryImplementationTest extends Bitrix24AccountRepositoryInterfaceTest +{ + protected function createBitrix24AccountImplementation( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): Bitrix24AccountInterface + { + return new Bitrix24AccountReferenceEntityImplementation( + $uuid, + $bitrix24UserId, + $isBitrix24UserAdmin, + $memberId, + $domainUrl, + $bitrix24AccountStatus, + $authToken, + $createdAt, + $updatedAt, + $applicationVersion, + $applicationScope + ); + } + + protected function createBitrix24AccountRepositoryImplementation(): Bitrix24AccountRepositoryInterface + { + return new InMemoryBitrix24AccountRepositoryImplementation(new NullLogger()); + } +} \ No newline at end of file diff --git a/tests/Unit/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterfaceReferenceImplementationTest.php b/tests/Unit/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterfaceReferenceImplementationTest.php new file mode 100644 index 00000000..ff52fb38 --- /dev/null +++ b/tests/Unit/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterfaceReferenceImplementationTest.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Application\Contracts\Bitrix24Partners\Entity; + +use Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Entity\Bitrix24PartnerInterface; +use Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Entity\Bitrix24PartnerStatus; +use Bitrix24\SDK\Tests\Application\Contracts\Bitrix24Partners\Entity\Bitrix24PartnerInterfaceTest; +use Carbon\CarbonImmutable; +use libphonenumber\PhoneNumber; +use PHPUnit\Framework\Attributes\CoversClass; +use Symfony\Component\Uid\Uuid; + +#[CoversClass(Bitrix24PartnerInterface::class)] +class Bitrix24PartnerInterfaceReferenceImplementationTest extends Bitrix24PartnerInterfaceTest +{ + protected function createBitrix24PartnerImplementation( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId): Bitrix24PartnerInterface + { + return new Bitrix24PartnerReferenceEntityImplementation( + $uuid, + $createdAt, + $updatedAt, + $bitrix24PartnerStatus, + $title, + $bitrix24PartnerId, + $site, + $phoneNumber, + $email, + $openLineId, + $externalId + ); + } +} \ No newline at end of file diff --git a/tests/Unit/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerReferenceEntityImplementation.php b/tests/Unit/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerReferenceEntityImplementation.php new file mode 100644 index 00000000..4684f69d --- /dev/null +++ b/tests/Unit/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerReferenceEntityImplementation.php @@ -0,0 +1,251 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Application\Contracts\Bitrix24Partners\Entity; + +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountInterface; +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountStatus; +use Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Entity\Bitrix24PartnerInterface; +use Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Entity\Bitrix24PartnerStatus; +use Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Events\Bitrix24PartnerExternalIdChangedEvent; +use Bitrix24\SDK\Application\Contracts\ContactPersons\Entity\ContactPersonStatus; +use Bitrix24\SDK\Application\Contracts\Events\AggregateRootEventsEmitterInterface; +use Bitrix24\SDK\Core\Credentials\AuthToken; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException; +use Bitrix24\SDK\Core\Response\DTO\RenewedAuthToken; +use Carbon\CarbonImmutable; +use libphonenumber\PhoneNumber; +use Symfony\Component\Uid\Uuid; +use Symfony\Contracts\EventDispatcher\Event; + +/** + * Class Bitrix24PartnerReferenceEntityImplementation + * + * This class uses ONLY for demonstration and tests interface, use cases for work with Bitrix24PartnerInterface methods + * + */ +final class Bitrix24PartnerReferenceEntityImplementation implements Bitrix24PartnerInterface, AggregateRootEventsEmitterInterface +{ + private ?string $comment = null; + + private array $events = []; + + public function __construct( + private readonly Uuid $id, + private readonly CarbonImmutable $createdAt, + private CarbonImmutable $updatedAt, + private Bitrix24PartnerStatus $bitrix24PartnerStatus, + private string $title, + private ?int $bitrix24PartnerId, + private ?string $site, + private ?PhoneNumber $phoneNumber, + private ?string $email, + private ?string $openLineId, + private ?string $externalId + ) + { + } + + public function emitEvents(): array + { + $events = $this->events; + $this->events = []; + return $events; + } + + public function getId(): Uuid + { + return $this->id; + } + + public function getExternalId(): ?string + { + return $this->externalId; + } + + public function setExternalId(?string $externalId): void + { + if ($externalId !== null && trim($externalId) === '') { + throw new InvalidArgumentException('externalId cannot be an empty string'); + } + + $prevExternalId = $this->externalId; + $this->externalId = $externalId; + $this->updatedAt = new CarbonImmutable(); + + $this->events[] = new Bitrix24PartnerExternalIdChangedEvent( + $this->id, + $this->updatedAt, + $prevExternalId, + $this->externalId + ); + } + + public function getTitle(): string + { + return $this->title; + } + + public function setTitle(string $title): void + { + if (trim($title) === '') { + throw new InvalidArgumentException('partner title cannot be an empty string'); + } + + $this->title = $title; + $this->updatedAt = new CarbonImmutable(); + } + + public function getSite(): ?string + { + return $this->site; + } + + public function setSite(?string $site): void + { + if ($site !== null && trim($site) === '') { + throw new InvalidArgumentException('site cannot be an empty string'); + } + + $this->site = $site; + $this->updatedAt = new CarbonImmutable(); + } + + public function getPhone(): ?PhoneNumber + { + return $this->phoneNumber; + } + + public function setPhone(?PhoneNumber $phoneNumber): void + { + $this->phoneNumber = $phoneNumber; + $this->updatedAt = new CarbonImmutable(); + } + + public function getEmail(): ?string + { + return $this->email; + } + + public function setEmail(?string $email): void + { + if ($email !== null && trim($email) === '') { + throw new InvalidArgumentException('email cannot be an empty string'); + } + + if ($email !== null && !filter_var($email, FILTER_VALIDATE_EMAIL)) { + throw new InvalidArgumentException(sprintf('invalid email «%s»', $email)); + } + + $this->email = $email; + $this->updatedAt = new CarbonImmutable(); + } + + public function getBitrix24PartnerId(): ?int + { + return $this->bitrix24PartnerId; + } + + public function setBitrix24PartnerId(?int $bitrix24PartnerId): void + { + if ($bitrix24PartnerId !== null && $bitrix24PartnerId <= 0) { + throw new InvalidArgumentException(sprintf('bitrix24 partner id must be positive int, now «%s»', $bitrix24PartnerId)); + } + + $this->bitrix24PartnerId = $bitrix24PartnerId; + $this->updatedAt = new CarbonImmutable(); + } + + public function getOpenLineId(): ?string + { + return $this->openLineId; + } + + public function setOpenLineId(?string $openLineId): void + { + if ($openLineId !== null && trim($openLineId) === '') { + throw new InvalidArgumentException('openLineId cannot be an empty string'); + } + + $this->openLineId = $openLineId; + $this->updatedAt = new CarbonImmutable(); + } + + public function getStatus(): Bitrix24PartnerStatus + { + return $this->bitrix24PartnerStatus; + } + + public function getCreatedAt(): CarbonImmutable + { + return $this->createdAt; + } + + public function getUpdatedAt(): CarbonImmutable + { + return $this->updatedAt; + } + + /** + * @throws InvalidArgumentException + */ + public function markAsActive(?string $comment): void + { + if (Bitrix24PartnerStatus::blocked !== $this->bitrix24PartnerStatus) { + throw new InvalidArgumentException( + sprintf('you can activate bitrix24 partner only in status blocked, now bitrix24 partner in status %s', + $this->bitrix24PartnerStatus->name)); + } + + $this->bitrix24PartnerStatus = Bitrix24PartnerStatus::active; + $this->comment = $comment; + $this->updatedAt = new CarbonImmutable(); + } + + /** + * @throws InvalidArgumentException + */ + public function markAsBlocked(?string $comment): void + { + if (Bitrix24PartnerStatus::deleted === $this->bitrix24PartnerStatus || Bitrix24PartnerStatus::blocked === $this->bitrix24PartnerStatus) { + throw new InvalidArgumentException( + sprintf('you cannot block bitrix24 partner in status «%s»', + $this->bitrix24PartnerStatus->name + )); + } + + $this->bitrix24PartnerStatus = Bitrix24PartnerStatus::blocked; + $this->comment = $comment; + $this->updatedAt = new CarbonImmutable(); + } + + public function markAsDeleted(?string $comment): void + { + if (Bitrix24PartnerStatus::deleted === $this->bitrix24PartnerStatus) { + throw new InvalidArgumentException( + sprintf('you cannot mark bitrix24 partner as deleted in status %s', + $this->bitrix24PartnerStatus->name)); + } + + $this->bitrix24PartnerStatus = Bitrix24PartnerStatus::deleted; + $this->comment = $comment; + $this->updatedAt = new CarbonImmutable(); + } + + public function getComment(): ?string + { + return $this->comment; + } +} diff --git a/tests/Unit/Application/Contracts/Bitrix24Partners/Repository/InMemoryBitrix24PartnerRepositoryImplementation.php b/tests/Unit/Application/Contracts/Bitrix24Partners/Repository/InMemoryBitrix24PartnerRepositoryImplementation.php new file mode 100644 index 00000000..ca6fc91f --- /dev/null +++ b/tests/Unit/Application/Contracts/Bitrix24Partners/Repository/InMemoryBitrix24PartnerRepositoryImplementation.php @@ -0,0 +1,163 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Application\Contracts\Bitrix24Partners\Repository; + +use Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Entity\Bitrix24PartnerInterface; +use Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Entity\Bitrix24PartnerStatus; +use Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Exceptions\Bitrix24PartnerNotFoundException; +use Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Repository\Bitrix24PartnerRepositoryInterface; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Psr\Log\LoggerInterface; +use Symfony\Component\Uid\Uuid; + +class InMemoryBitrix24PartnerRepositoryImplementation implements Bitrix24PartnerRepositoryInterface +{ + /** + * @var Bitrix24PartnerInterface[] + */ + private array $items = []; + + public function __construct( + private readonly LoggerInterface $logger + ) + { + } + + public function findByBitrix24PartnerId(int $bitrix24PartnerId): ?Bitrix24PartnerInterface + { + $this->logger->debug('b24PartnerRepository.findByBitrix24PartnerId', [ + 'bitrix24PartnerId' => $bitrix24PartnerId + ]); + + foreach ($this->items as $item) { + if ($item->getBitrix24PartnerId() === $bitrix24PartnerId) { + $this->logger->debug('b24PartnerRepository.findByBitrix24PartnerId.found', [ + 'id' => $item->getId()->toRfc4122() + ]); + return $item; + } + } + + return null; + } + + /** + * @throws InvalidArgumentException + */ + public function findByTitle(string $title): array + { + $this->logger->debug('b24PartnerRepository.findByTitle', [ + 'title' => $title + ]); + + if (trim($title) === '') { + throw new InvalidArgumentException('you cant find by empty title'); + } + + $title = strtolower(trim($title)); + + $items = []; + foreach ($this->items as $item) { + if (strtolower($item->getTitle()) === $title) { + $this->logger->debug('b24PartnerRepository.findByTitle.found', [ + 'id' => $item->getId()->toRfc4122() + ]); + $items[] = $item; + } + } + + return $items; + } + + public function findByExternalId(string $externalId, ?Bitrix24PartnerStatus $bitrix24PartnerStatus = null): array + { + $this->logger->debug('b24PartnerRepository.findByExternalId', [ + 'externalId' => $externalId, + 'bitrix24PartnerStatus' => $bitrix24PartnerStatus?->name + ]); + + if (trim($externalId) === '') { + throw new InvalidArgumentException('you cant find by empty externalId'); + } + + $externalId = trim($externalId); + + $items = []; + foreach ($this->items as $item) { + if ($item->getExternalId() === $externalId && (is_null($bitrix24PartnerStatus) || $item->getStatus() === $bitrix24PartnerStatus)) { + $this->logger->debug('b24PartnerRepository.findByExternalId.found', [ + 'id' => $item->getId()->toRfc4122() + ]); + $items[] = $item; + } + } + + return $items; + } + + /** + * @throws InvalidArgumentException + */ + public function save(Bitrix24PartnerInterface $bitrix24Partner): void + { + $this->logger->debug('b24PartnerRepository.save', [ + 'id' => $bitrix24Partner->getId()->toRfc4122(), + 'bitrix24PartnerId' => $bitrix24Partner->getBitrix24PartnerId() + ]); + + if ($bitrix24Partner->getBitrix24PartnerId() === null) { + $this->items[$bitrix24Partner->getId()->toRfc4122()] = $bitrix24Partner; + return; + } + + $existsPartner = $this->findByBitrix24PartnerId($bitrix24Partner->getBitrix24PartnerId()); + if ($existsPartner instanceof Bitrix24PartnerInterface && $existsPartner->getId() !== $bitrix24Partner->getId()) { + throw new InvalidArgumentException(sprintf( + 'bitrix24 partner «%s» with bitrix24 partner id is «%s» already exists with id «%s» in status «%s»', + $existsPartner->getTitle(), + $bitrix24Partner->getBitrix24PartnerId(), + $existsPartner->getId(), + $existsPartner->getStatus()->name + )); + } + + $this->items[$bitrix24Partner->getId()->toRfc4122()] = $bitrix24Partner; + } + + public function delete(Uuid $uuid): void + { + $this->logger->debug('b24PartnerRepository.delete', ['id' => $uuid->toRfc4122()]); + + $bitrix24Partner = $this->getById($uuid); + if (Bitrix24PartnerStatus::deleted !== $bitrix24Partner->getStatus()) { + throw new InvalidArgumentException(sprintf('you cannot delete bitrix24 partner item «%s», they must be in status deleted, current status «%s»', + $bitrix24Partner->getId()->toRfc4122(), + $bitrix24Partner->getStatus()->name + )); + } + + unset($this->items[$uuid->toRfc4122()]); + } + + public function getById(Uuid $uuid): Bitrix24PartnerInterface + { + $this->logger->debug('b24PartnerRepository.getById', ['id' => $uuid->toRfc4122()]); + + if (!array_key_exists($uuid->toRfc4122(), $this->items)) { + throw new Bitrix24PartnerNotFoundException(sprintf('bitrix24 partner not found by id «%s» ', $uuid->toRfc4122())); + } + + return $this->items[$uuid->toRfc4122()]; + } +} \ No newline at end of file diff --git a/tests/Unit/Application/Contracts/Bitrix24Partners/Repository/InMemoryBitrix24PartnerRepositoryImplementationTest.php b/tests/Unit/Application/Contracts/Bitrix24Partners/Repository/InMemoryBitrix24PartnerRepositoryImplementationTest.php new file mode 100644 index 00000000..29536918 --- /dev/null +++ b/tests/Unit/Application/Contracts/Bitrix24Partners/Repository/InMemoryBitrix24PartnerRepositoryImplementationTest.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Application\Contracts\Bitrix24Partners\Repository; + +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountInterface; +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountStatus; +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Repository\Bitrix24AccountRepositoryInterface; +use Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Entity\Bitrix24PartnerInterface; +use Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Entity\Bitrix24PartnerStatus; +use Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Repository\Bitrix24PartnerRepositoryInterface; +use Bitrix24\SDK\Application\Contracts\ContactPersons\Entity\ContactPersonInterface; +use Bitrix24\SDK\Application\Contracts\ContactPersons\Entity\ContactPersonStatus; +use Bitrix24\SDK\Application\Contracts\ContactPersons\Repository\ContactPersonRepositoryInterface; +use Bitrix24\SDK\Core\Credentials\AuthToken; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Tests\Application\Contracts\Bitrix24Partners\Repository\Bitrix24PartnerRepositoryInterfaceTest; +use Bitrix24\SDK\Tests\Application\Contracts\ContactPersons\Repository\ContactPersonRepositoryInterfaceTest; +use Bitrix24\SDK\Tests\Integration\Fabric; +use Bitrix24\SDK\Tests\Unit\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountReferenceEntityImplementation; +use Bitrix24\SDK\Tests\Unit\Application\Contracts\Bitrix24Partners\Entity\Bitrix24PartnerReferenceEntityImplementation; +use Bitrix24\SDK\Tests\Unit\Application\Contracts\ContactPersons\Entity\ContactPersonReferenceEntityImplementation; +use Bitrix24\SDK\Tests\Unit\Application\Contracts\ContactPersons\Repository\InMemoryContactPersonRepositoryImplementation; +use Carbon\CarbonImmutable; +use Darsyn\IP\Version\Multi as IP; +use libphonenumber\PhoneNumber; +use PHPUnit\Framework\Attributes\CoversClass; +use Psr\Log\NullLogger; +use Symfony\Component\Uid\Uuid; + +#[CoversClass(Bitrix24PartnerRepositoryInterface::class)] +class InMemoryBitrix24PartnerRepositoryImplementationTest extends Bitrix24PartnerRepositoryInterfaceTest +{ + protected function createBitrix24PartnerImplementation( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + Bitrix24PartnerStatus $bitrix24PartnerStatus, + string $title, + ?int $bitrix24PartnerId, + ?string $site, + ?PhoneNumber $phoneNumber, + ?string $email, + ?string $openLineId, + ?string $externalId): Bitrix24PartnerInterface + { + return new Bitrix24PartnerReferenceEntityImplementation( + $uuid, + $createdAt, + $updatedAt, + $bitrix24PartnerStatus, + $title, + $bitrix24PartnerId, + $site, + $phoneNumber, + $email, + $openLineId, + $externalId); + } + + protected function createBitrix24PartnerRepositoryImplementation(): Bitrix24PartnerRepositoryInterface + { + return new InMemoryBitrix24PartnerRepositoryImplementation(new NullLogger()); + } +} \ No newline at end of file diff --git a/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceReferenceImplementationTest.php b/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceReferenceImplementationTest.php new file mode 100644 index 00000000..58032148 --- /dev/null +++ b/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceReferenceImplementationTest.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Application\Contracts\ContactPersons\Entity; + +use Bitrix24\SDK\Application\Contracts\ContactPersons\Entity\ContactPersonInterface; +use Bitrix24\SDK\Application\Contracts\ContactPersons\Entity\ContactPersonStatus; +use Bitrix24\SDK\Tests\Application\Contracts\ContactPersons\Entity\ContactPersonInterfaceTest; +use Carbon\CarbonImmutable; +use Darsyn\IP\Version\Multi as IP; +use libphonenumber\PhoneNumber; +use PHPUnit\Framework\Attributes\CoversClass; +use Symfony\Component\Uid\Uuid; + +#[CoversClass(ContactPersonReferenceEntityImplementation::class)] +class ContactPersonInterfaceReferenceImplementationTest extends ContactPersonInterfaceTest +{ + protected function createContactPersonImplementation( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): ContactPersonInterface + { + return new ContactPersonReferenceEntityImplementation( + $uuid, + $createdAt, + $updatedAt, + $contactPersonStatus, + $name, + $surname, + $patronymic, + $email, + $emailVerifiedAt, + $comment, + $phoneNumber, + $mobilePhoneVerifiedAt, + $externalId, + $bitrix24UserId, + $bitrix24PartnerUuid, + $userAgent, + $userAgentReferer, + $userAgentIp + ); + } +} \ No newline at end of file diff --git a/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonReferenceEntityImplementation.php b/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonReferenceEntityImplementation.php new file mode 100644 index 00000000..2a72c5ac --- /dev/null +++ b/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonReferenceEntityImplementation.php @@ -0,0 +1,225 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Application\Contracts\ContactPersons\Entity; + +use Bitrix24\SDK\Application\Contracts\ContactPersons\Entity\ContactPersonInterface; +use Bitrix24\SDK\Application\Contracts\ContactPersons\Entity\ContactPersonStatus; +use Bitrix24\SDK\Application\Contracts\ContactPersons\Entity\FullName; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Carbon\CarbonImmutable; +use Darsyn\IP\Version\Multi as IP; +use libphonenumber\PhoneNumber; +use Symfony\Component\Uid\Uuid; + +/** + * This class uses ONLY for demonstration and tests interface, use cases for work with Bitrix24AccountInterface methods + */ +final class ContactPersonReferenceEntityImplementation implements ContactPersonInterface +{ + public function __construct( + private readonly Uuid $id, + private readonly CarbonImmutable $createdAt, + private CarbonImmutable $updatedAt, + private ContactPersonStatus $contactPersonStatus, + private string $name, + private ?string $surname, + private ?string $patronymic, + private ?string $email, + private ?CarbonImmutable $emailVerifiedAt, + private ?string $comment, + private ?PhoneNumber $mobilePhone, + private ?CarbonImmutable $mobilePhoneVerifiedAt, + private ?string $externalId, + private readonly ?int $bitrix24UserId, + private ?Uuid $bitrix24PartnerUuid, + private readonly ?string $userAgent, + private readonly ?string $userAgentReferer, + private readonly ?IP $userAgentIp + ) + { + } + + public function getId(): Uuid + { + return $this->id; + } + + public function getStatus(): ContactPersonStatus + { + return $this->contactPersonStatus; + } + + public function markAsActive(?string $comment): void + { + if (ContactPersonStatus::blocked !== $this->contactPersonStatus) { + throw new InvalidArgumentException( + sprintf('you can activate account only in status blocked, now account in status %s', + $this->contactPersonStatus->name)); + } + + $this->contactPersonStatus = ContactPersonStatus::active; + $this->comment = $comment; + $this->updatedAt = new CarbonImmutable(); + } + + public function markAsDeleted(?string $comment): void + { + if (ContactPersonStatus::deleted === $this->contactPersonStatus) { + throw new InvalidArgumentException( + sprintf('you cannot mark account as deleted in status %s', + $this->contactPersonStatus->name)); + } + + $this->contactPersonStatus = ContactPersonStatus::deleted; + $this->comment = $comment; + $this->updatedAt = new CarbonImmutable(); + } + + /** + * @throws InvalidArgumentException + */ + public function markAsBlocked(?string $comment): void + { + if (ContactPersonStatus::deleted === $this->contactPersonStatus) { + throw new InvalidArgumentException('you cannot block contact person in status «deleted»'); + } + + $this->contactPersonStatus = ContactPersonStatus::blocked; + $this->comment = $comment; + $this->updatedAt = new CarbonImmutable(); + } + + public function getFullName(): FullName + { + return new FullName($this->name, $this->surname, $this->patronymic); + } + + public function changeFullName(FullName $fullName): void + { + $this->name = $fullName->name; + $this->surname = $fullName->surname; + $this->patronymic = $fullName->patronymic; + $this->updatedAt = new CarbonImmutable(); + } + + public function getCreatedAt(): CarbonImmutable + { + return $this->createdAt; + } + + public function getUpdatedAt(): CarbonImmutable + { + return $this->updatedAt; + } + + public function changeEmail(?string $email, ?bool $isEmailVerified = null): void + { + $this->emailVerifiedAt = null; + $this->email = $email; + if ($isEmailVerified === true) { + $this->emailVerifiedAt = new CarbonImmutable(); + } + + $this->updatedAt = new CarbonImmutable(); + } + + public function getEmail(): ?string + { + return $this->email; + } + + public function getEmailVerifiedAt(): ?CarbonImmutable + { + return $this->emailVerifiedAt; + } + + public function markEmailAsVerified(): void + { + $this->emailVerifiedAt = new CarbonImmutable(); + $this->updatedAt = new CarbonImmutable(); + } + + public function changeMobilePhone(?PhoneNumber $phoneNumber, ?bool $isMobilePhoneVerified = null): void + { + $this->mobilePhoneVerifiedAt = null; + $this->mobilePhone = $phoneNumber; + if ($isMobilePhoneVerified === true) { + $this->mobilePhoneVerifiedAt = new CarbonImmutable(); + } + + $this->updatedAt = new CarbonImmutable(); + } + + public function getMobilePhone(): ?PhoneNumber + { + return $this->mobilePhone; + } + + public function getMobilePhoneVerifiedAt(): ?CarbonImmutable + { + return $this->mobilePhoneVerifiedAt; + } + + public function markMobilePhoneAsVerified(): void + { + $this->mobilePhoneVerifiedAt = new CarbonImmutable(); + $this->updatedAt = new CarbonImmutable(); + } + + public function getComment(): ?string + { + return $this->comment; + } + + public function setExternalId(?string $externalId): void + { + $this->externalId = $externalId; + $this->updatedAt = new CarbonImmutable(); + } + + public function getExternalId(): ?string + { + return $this->externalId; + } + + public function getBitrix24UserId(): ?int + { + return $this->bitrix24UserId; + } + + public function getBitrix24PartnerId(): ?Uuid + { + return $this->bitrix24PartnerUuid; + } + + public function setBitrix24PartnerId(?Uuid $uuid): void + { + $this->bitrix24PartnerUuid = $uuid; + } + + public function getUserAgent(): ?string + { + return $this->userAgent; + } + + public function getUserAgentReferer(): ?string + { + return $this->userAgentReferer; + } + + public function getUserAgentIp(): ?IP + { + return $this->userAgentIp; + } +} diff --git a/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementation.php b/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementation.php new file mode 100644 index 00000000..6d710b7a --- /dev/null +++ b/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementation.php @@ -0,0 +1,139 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Application\Contracts\ContactPersons\Repository; + +use Bitrix24\SDK\Application\Contracts\ContactPersons\Entity\ContactPersonInterface; +use Bitrix24\SDK\Application\Contracts\ContactPersons\Entity\ContactPersonStatus; +use Bitrix24\SDK\Application\Contracts\ContactPersons\Exceptions\ContactPersonNotFoundException; +use Bitrix24\SDK\Application\Contracts\ContactPersons\Repository\ContactPersonRepositoryInterface; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use libphonenumber\PhoneNumber; +use Psr\Log\LoggerInterface; +use Symfony\Component\Uid\Uuid; + + +class InMemoryContactPersonRepositoryImplementation implements ContactPersonRepositoryInterface +{ + /** + * @var ContactPersonInterface[] + */ + private array $items = []; + + public function __construct( + private readonly LoggerInterface $logger + ) + { + } + + public function save(ContactPersonInterface $contactPerson): void + { + $this->logger->debug('InMemoryContactPersonRepositoryImplementation.save', ['id' => $contactPerson->getId()->toRfc4122()]); + + $this->items[$contactPerson->getId()->toRfc4122()] = $contactPerson; + } + + public function delete(Uuid $uuid): void + { + $this->logger->debug('InMemoryContactPersonRepositoryImplementation.delete', ['id' => $uuid->toRfc4122()]); + + $contactPerson = $this->getById($uuid); + if (ContactPersonStatus::deleted !== $contactPerson->getStatus()) { + throw new InvalidArgumentException(sprintf('you cannot delete contact person «%s», in status «%s», mark contact person as deleted before', + $contactPerson->getId()->toRfc4122(), + $contactPerson->getStatus()->name, + )); + } + + unset($this->items[$uuid->toRfc4122()]); + } + + /** + * @throws ContactPersonNotFoundException + */ + public function getById(Uuid $uuid): ContactPersonInterface + { + $this->logger->debug('InMemoryContactPersonRepositoryImplementation.getById', ['id' => $uuid->toRfc4122()]); + + if (!array_key_exists($uuid->toRfc4122(), $this->items)) { + throw new ContactPersonNotFoundException(sprintf('contact person not found by id «%s» ', $uuid->toRfc4122())); + } + + return $this->items[$uuid->toRfc4122()]; + } + + public function findByEmail(string $email, ?ContactPersonStatus $contactPersonStatus = null, ?bool $isEmailVerified = null): array + { + $result = []; + foreach ($this->items as $item) { + if ($email !== $item->getEmail()) { + continue; + } + + if ($contactPersonStatus instanceof ContactPersonStatus && $contactPersonStatus !== $item->getStatus()) { + continue; + } + + if ($isEmailVerified !== null && $isEmailVerified !== ($item->getEmailVerifiedAt() !== null)) { + continue; + } + + $result[] = $item; + } + + return $result; + } + + public function findByPhone(PhoneNumber $phoneNumber, ?ContactPersonStatus $contactPersonStatus = null, ?bool $isPhoneVerified = null): array + { + $result = []; + foreach ($this->items as $item) { + if ($phoneNumber !== $item->getMobilePhone()) { + continue; + } + + if ($contactPersonStatus instanceof ContactPersonStatus && $contactPersonStatus !== $item->getStatus()) { + continue; + } + + if ($isPhoneVerified !== null && $isPhoneVerified !== ($item->getMobilePhoneVerifiedAt() !== null)) { + continue; + } + + $result[] = $item; + } + + return $result; + } + + public function findByExternalId(string $externalId, ?ContactPersonStatus $contactPersonStatus = null): array + { + $externalId = trim($externalId); + if ($externalId === '') { + throw new InvalidArgumentException('externalId cannot be empty'); + } + + $result = []; + foreach ($this->items as $item) { + if ($contactPersonStatus instanceof ContactPersonStatus && $contactPersonStatus !== $item->getStatus()) { + continue; + } + + if ($externalId === $item->getExternalId()) { + $result[] = $item; + } + } + + return $result; + } +} \ No newline at end of file diff --git a/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementationTest.php b/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementationTest.php new file mode 100644 index 00000000..3c4ed448 --- /dev/null +++ b/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementationTest.php @@ -0,0 +1,113 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Application\Contracts\ContactPersons\Repository; + +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountInterface; +use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountStatus; +use Bitrix24\SDK\Application\Contracts\ContactPersons\Entity\ContactPersonInterface; +use Bitrix24\SDK\Application\Contracts\ContactPersons\Entity\ContactPersonStatus; +use Bitrix24\SDK\Application\Contracts\ContactPersons\Repository\ContactPersonRepositoryInterface; +use Bitrix24\SDK\Core\Credentials\AuthToken; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Tests\Application\Contracts\ContactPersons\Repository\ContactPersonRepositoryInterfaceTest; +use Bitrix24\SDK\Tests\Integration\Fabric; +use Bitrix24\SDK\Tests\Unit\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountReferenceEntityImplementation; +use Bitrix24\SDK\Tests\Unit\Application\Contracts\ContactPersons\Entity\ContactPersonReferenceEntityImplementation; +use Carbon\CarbonImmutable; +use Darsyn\IP\Version\Multi as IP; +use libphonenumber\PhoneNumber; +use PHPUnit\Framework\Attributes\CoversClass; +use Psr\Log\NullLogger; +use Symfony\Component\Uid\Uuid; + +#[CoversClass(ContactPersonRepositoryInterface::class)] +class InMemoryContactPersonRepositoryImplementationTest extends ContactPersonRepositoryInterfaceTest +{ + protected function createBitrix24AccountImplementation( + Uuid $uuid, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $bitrix24AccountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): Bitrix24AccountInterface + { + return new Bitrix24AccountReferenceEntityImplementation( + $uuid, + $bitrix24UserId, + $isBitrix24UserAdmin, + $memberId, + $domainUrl, + $bitrix24AccountStatus, + $authToken, + $createdAt, + $updatedAt, + $applicationVersion, + $applicationScope + ); + } + + protected function createContactPersonImplementation( + Uuid $uuid, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $phoneNumber, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): ContactPersonInterface + { + return new ContactPersonReferenceEntityImplementation( + $uuid, + $createdAt, + $updatedAt, + $contactPersonStatus, + $name, + $surname, + $patronymic, + $email, + $emailVerifiedAt, + $comment, + $phoneNumber, + $mobilePhoneVerifiedAt, + $externalId, + $bitrix24UserId, + $bitrix24PartnerId, + $userAgent, + $userAgentReferer, + $userAgentIp + ); + } + + protected function createContactPersonRepositoryImplementation(): ContactPersonRepositoryInterface + { + return new InMemoryContactPersonRepositoryImplementation(new NullLogger()); + } +} \ No newline at end of file diff --git a/tests/Unit/Core/ApiLevelErrorHandlerTest.php b/tests/Unit/Core/ApiLevelErrorHandlerTest.php new file mode 100644 index 00000000..63c5b20e --- /dev/null +++ b/tests/Unit/Core/ApiLevelErrorHandlerTest.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Core; + +use Bitrix24\SDK\Core\ApiLevelErrorHandler; +use Bitrix24\SDK\Core\CoreBuilder; +use Bitrix24\SDK\Core\Credentials\Credentials; +use Bitrix24\SDK\Core\Credentials\WebhookUrl; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\OperationTimeLimitExceededException; +use Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException; +use PHPUnit\Framework\TestCase; +use Psr\Log\NullLogger; + +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Core\ApiLevelErrorHandler::class)] +class ApiLevelErrorHandlerTest extends TestCase +{ + private ApiLevelErrorHandler $apiLevelErrorHandler; + + /** + * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\QueryLimitExceededException + */ + #[\PHPUnit\Framework\Attributes\TestDox('Test operating error in bach mode')] + public function testOperatingErrorInBachMode(): void + { + $this->expectException(OperationTimeLimitExceededException::class); + + $response = [ + 'result' => [ + 'result' => [], + 'result_error' => [ + "592dcd1e-cd14-410f-bab5-76b3ede717dd" => [ + 'error' => 'OPERATION_TIME_LIMIT', + 'error_description' => 'Method is blocked due to operation time limit.' + ] + ] + ], + ]; + + $this->apiLevelErrorHandler->handle($response); + } + + protected function setUp(): void + { + $this->apiLevelErrorHandler = new ApiLevelErrorHandler(new NullLogger()); + } +} diff --git a/tests/Unit/Core/CoreBuilderTest.php b/tests/Unit/Core/CoreBuilderTest.php new file mode 100644 index 00000000..c7926e5e --- /dev/null +++ b/tests/Unit/Core/CoreBuilderTest.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Core; + +use Bitrix24\SDK\Core\CoreBuilder; +use Bitrix24\SDK\Core\Credentials\Credentials; +use Bitrix24\SDK\Core\Credentials\WebhookUrl; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException; +use PHPUnit\Framework\TestCase; + +class CoreBuilderTest extends TestCase +{ + /** + * @throws UnknownScopeCodeException + * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + */ + public function testBuildWithCredentialsFromWebhook(): void + { + (new CoreBuilder()) + ->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); + (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..823ef7fa --- /dev/null +++ b/tests/Unit/Core/Credentials/ApplicationProfileTest.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Core\Credentials; + +use Bitrix24\SDK\Core\Credentials\ApplicationProfile; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Generator; +use PHPUnit\Framework\TestCase; + +class ApplicationProfileTest extends TestCase +{ + /** + * + * + * @throws InvalidArgumentException + */ + #[\PHPUnit\Framework\Attributes\DataProvider('arrayDataProvider')] + public function testFromArray(array $arr, ?string $expectedException): void + { + if ($expectedException !== null) { + $this->expectException($expectedException); + } + + $applicationProfile = ApplicationProfile::initFromArray($arr); + + $this->assertEquals($applicationProfile->getClientId(), $arr['BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID']); + $this->assertEquals($applicationProfile->getClientSecret(), $arr['BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET']); + } + + public static 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, + ]; + yield 'with empty scope' => [ + [ + 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID' => '1', + 'BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET' => '2', + 'BITRIX24_PHP_SDK_APPLICATION_SCOPE' => '', + ], + null + ]; + } +} diff --git a/tests/Unit/Core/Credentials/CredentialsTest.php b/tests/Unit/Core/Credentials/CredentialsTest.php new file mode 100644 index 00000000..5085fa59 --- /dev/null +++ b/tests/Unit/Core/Credentials/CredentialsTest.php @@ -0,0 +1,119 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Core\Credentials; + +use Bitrix24\SDK\Core\Credentials\AuthToken; +use Bitrix24\SDK\Core\Credentials\ApplicationProfile; +use Bitrix24\SDK\Core\Credentials\Credentials; +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Credentials\WebhookUrl; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException; +use Generator; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; +#[CoversClass(Credentials::class)] +class CredentialsTest extends TestCase +{ + #[Test] + #[TestDox('tests get domain url')] + #[DataProvider('credentialsDataProviderWithDomainUrlVariants')] + public function testGetDomainUrl( + Credentials $credentials, + string $expectedDomainUrl + ): void { + $this->assertEquals($expectedDomainUrl, $credentials->getDomainUrl()); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownScopeCodeException + */ + #[Test] + #[TestDox('tests get domain url without protocol')] + public function testDomainUrlWithoutProtocol(): void + { + $credentials = Credentials::createFromOAuth( + new AuthToken('', '', 0), + new ApplicationProfile('', '', new Scope(['crm'])), + 'bitrix24-php-sdk-playground.bitrix24.ru' + ); + $this->assertEquals( + 'https://bitrix24-php-sdk-playground.bitrix24.ru', + $credentials->getDomainUrl() + ); + } + + #[Test] + #[TestDox('tests isWebhookContext')] + public function testIsWebhookContext():void + { + $credentials = Credentials::createFromOAuth( + new AuthToken('', '', 0), + new ApplicationProfile('', '', new Scope(['crm'])), + 'bitrix24-php-sdk-playground.bitrix24.ru' + ); + $this->assertFalse($credentials->isWebhookContext()); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownScopeCodeException + */ + #[Test] + #[TestDox('tests domain url with protocol')] + public function testDomainUrlWithProtocol(): void + { + $credentials = Credentials::createFromOAuth( + new AuthToken('', '', 0), + new ApplicationProfile('', '', new Scope(['crm'])), + 'https://bitrix24-php-sdk-playground.bitrix24.ru' + ); + $this->assertEquals( + 'https://bitrix24-php-sdk-playground.bitrix24.ru', + $credentials->getDomainUrl() + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownScopeCodeException + */ + public static 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 AuthToken('', '', 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 AuthToken('', '', 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/Credentials/ScopeTest.php b/tests/Unit/Core/Credentials/ScopeTest.php new file mode 100644 index 00000000..96cbdb9a --- /dev/null +++ b/tests/Unit/Core/Credentials/ScopeTest.php @@ -0,0 +1,121 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Core\Credentials; + +use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException; +use PHPUnit\Framework\TestCase; + +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Core\Credentials\Scope::class)] +class ScopeTest extends TestCase +{ + /** + * @throws UnknownScopeCodeException + */ + public function testBuildScopeFromArray(): void + { + $availableScope = [ + 'bizproc', + 'calendar', + 'call', + 'contact_center', + 'crm', + 'delivery', + 'department', + 'disk', + 'documentgenerator', + 'entity', + 'faceid', + 'forum', + 'im', + 'imbot', + 'imopenlines', + 'intranet', + 'landing', + 'landing_cloud', + 'lists', + 'log', + 'mailservice', + 'messageservice', + 'mobile', + 'pay_system', + 'placement', + 'pull', + 'pull_channel', + 'rating', + 'sale', + 'smile', + 'sonet_group', + 'task', + 'tasks_extended', + 'telephony', + 'timeman', + 'user', + 'userconsent', + ]; + $scope = new Scope($availableScope); + $this->assertEquals($availableScope, $scope->getScopeCodes()); + } + + /** + * @throws UnknownScopeCodeException + */ + public function testUnknownScope(): void + { + $this->expectException(UnknownScopeCodeException::class); + + new Scope(['fooo']); + } + + /** + * @throws UnknownScopeCodeException + */ + public function testEqual(): void + { + $scope = Scope::initFromString('crm,telephony'); + $this->assertTrue($scope->equal(Scope::initFromString('telephony,crm'))); + $this->assertFalse($scope->equal(Scope::initFromString('telephony'))); + } + + /** + * @throws UnknownScopeCodeException + */ + public function testEmptyScope(): void + { + $scope = new Scope(['']); + $this->assertEquals([], $scope->getScopeCodes()); + } + + /** + * @throws UnknownScopeCodeException + */ + public function testWrongScopeCode(): void + { + $scope = new Scope(['CRM', 'Call', 'im']); + + $this->assertEquals(['call', 'crm', 'im'], $scope->getScopeCodes()); + } + + /** + * @throws UnknownScopeCodeException + */ + #[\PHPUnit\Framework\Attributes\TestDox('Test init Scope from string')] + public function testInitFromString(): void + { + $scopeList = ['crm', 'telephony', 'call', 'user_basic', 'placement', 'im', 'imopenlines']; + sort($scopeList); + $scope = Scope::initFromString('crm,telephony,call,user_basic,placement,im,imopenlines'); + $this->assertEquals($scopeList, $scope->getScopeCodes()); + } +} diff --git a/tests/Unit/Core/Credentials/WebhookUrlTest.php b/tests/Unit/Core/Credentials/WebhookUrlTest.php new file mode 100644 index 00000000..0342277c --- /dev/null +++ b/tests/Unit/Core/Credentials/WebhookUrlTest.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Core\Credentials; + +use Bitrix24\SDK\Core\Credentials\WebhookUrl; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use PHPUnit\Framework\TestCase; + +/** + * Class ScopeTest + * + * @package Bitrix24\SDK\Tests\Unit\Core + */ +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Core\Credentials\WebhookUrl::class)] +class WebhookUrlTest extends TestCase +{ + #[\PHPUnit\Framework\Attributes\TestDox('Test valid webhook url')] + public function testValidWebhookUrl(): void + { + new WebhookUrl('https://bitrix24.ru/'); + $this->assertTrue(true); + } + + #[\PHPUnit\Framework\Attributes\TestDox('Test invalid webhook url')] + public function testInvalidWebhookUrl(): void + { + $this->expectException(InvalidArgumentException::class); + new WebhookUrl('qqqq'); + } +} diff --git a/tests/Unit/Core/Response/DTO/TimeTest.php b/tests/Unit/Core/Response/DTO/TimeTest.php new file mode 100644 index 00000000..fee29aef --- /dev/null +++ b/tests/Unit/Core/Response/DTO/TimeTest.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Core\Response\DTO; + +use Bitrix24\SDK\Core\Response\DTO\Time; +use Generator; +use PHPUnit\Framework\TestCase; + +/** + * Class TimeTest + * + * @package Bitrix24\SDK\Tests\Unit\Core\Response\DTO + */ +class TimeTest extends TestCase +{ + /** + * @throws \Exception + */ + #[\PHPUnit\Framework\Attributes\DataProvider('timingsDataProvider')] + public function testInitFromResponseData(array $result): void + { + $time = Time::initFromResponse($result); + + $this->assertEquals($result['start'], $time->start); + $this->assertEquals($result['finish'], $time->finish); + $this->assertEquals($result['duration'], $time->duration); + $this->assertEquals($result['processing'], $time->processing); + $this->assertEquals($result['operating'], $time->operating); + $this->assertEquals($result['operating_reset_at'], $time->operatingResetAt); + $this->assertEquals($result['date_start'], $time->dateStart->format(\DATE_ATOM)); + $this->assertEquals($result['date_finish'], $time->dateFinish->format(\DATE_ATOM)); + } + + public static 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/Core/Result/AbstractItemTest.php b/tests/Unit/Core/Result/AbstractItemTest.php new file mode 100644 index 00000000..6468cb85 --- /dev/null +++ b/tests/Unit/Core/Result/AbstractItemTest.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Core\Result; + +use Bitrix24\SDK\Core\Exceptions\ImmutableResultViolationException; +use Bitrix24\SDK\Core\Result\AbstractItem; +use PHPUnit\Framework\TestCase; + +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Core\Result\AbstractItem::class)] +class AbstractItemTest extends TestCase +{ + public function testSetPropertyItem(): void + { + $this->expectException(ImmutableResultViolationException::class); + $testClassForAbstractItem = new TestClassForAbstractItem(['ID'=>1]); + $testClassForAbstractItem->ID = 2; + } + + public function testUnsetPropertyItem(): void + { + $this->expectException(ImmutableResultViolationException::class); + $testClassForAbstractItem = new TestClassForAbstractItem(['ID'=>1]); + unset($testClassForAbstractItem->ID); + } +} + +/** + * @property int $ID + */ +class TestClassForAbstractItem extends AbstractItem +{ +} \ No newline at end of file diff --git a/tests/Unit/Infrastructure/HttpClient/RequestId/DefaultRequestIdGeneratorTest.php b/tests/Unit/Infrastructure/HttpClient/RequestId/DefaultRequestIdGeneratorTest.php new file mode 100644 index 00000000..6946ec71 --- /dev/null +++ b/tests/Unit/Infrastructure/HttpClient/RequestId/DefaultRequestIdGeneratorTest.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Infrastructure\HttpClient\RequestId; + +use Bitrix24\SDK\Infrastructure\HttpClient\RequestId\DefaultRequestIdGenerator; +use Generator; +use PHPUnit\Framework\TestCase; +use Symfony\Component\Uid\Uuid; + +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Infrastructure\HttpClient\RequestId\DefaultRequestIdGenerator::class)] +class DefaultRequestIdGeneratorTest extends TestCase +{ + /** + * @param $requestIdKey + * @param $requestId + */ + #[\PHPUnit\Framework\Attributes\DataProvider('requestIdKeyDataProvider')] + public function testExistsRequestId(string $requestIdKey, string $requestId): void + { + $_SERVER[$requestIdKey] = $requestId; + $defaultRequestIdGenerator = new DefaultRequestIdGenerator(); + $this->assertEquals($requestId, $defaultRequestIdGenerator->getRequestId()); + unset($_SERVER[$requestIdKey]); + } + + public static function requestIdKeyDataProvider(): Generator + { + yield 'REQUEST_ID' => [ + 'REQUEST_ID', + Uuid::v7()->toRfc4122() + ]; + yield 'HTTP_X_REQUEST_ID' => [ + 'HTTP_X_REQUEST_ID', + Uuid::v7()->toRfc4122() + ]; + yield 'UNIQUE_ID' => [ + 'UNIQUE_ID', + Uuid::v7()->toRfc4122() + ]; + } +} diff --git a/tests/Unit/Services/CRM/CRMServiceBuilderTest.php b/tests/Unit/Services/CRM/CRMServiceBuilderTest.php new file mode 100644 index 00000000..e7819d61 --- /dev/null +++ b/tests/Unit/Services/CRM/CRMServiceBuilderTest.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Services\CRM; + +use Bitrix24\SDK\Services\CRM\CRMServiceBuilder; +use Bitrix24\SDK\Services\ServiceBuilder; +use Bitrix24\SDK\Tests\Unit\Stubs\NullBatch; +use Bitrix24\SDK\Tests\Unit\Stubs\NullBulkItemsReader; +use Bitrix24\SDK\Tests\Unit\Stubs\NullCore; +use PHPUnit\Framework\TestCase; +use Psr\Log\NullLogger; + +/** + * Class CRMServiceBuilderTest + * + * @package Bitrix24\SDK\Tests\Unit\Services\CRM + */ +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\CRM\CRMServiceBuilder::class)] +class CRMServiceBuilderTest extends TestCase +{ + private CRMServiceBuilder $serviceBuilder; + + public function testGetSettingsService(): void + { + $this->serviceBuilder->settings(); + $this::assertTrue(true); + } + + public function testGetDealContactService(): void + { + $this->serviceBuilder->dealContact(); + $this::assertTrue(true); + } + + public function testGetDealCategoryService(): void + { + $this->serviceBuilder->dealCategory(); + $this::assertTrue(true); + } + + public function testDealService(): void + { + $this->serviceBuilder->deal(); + $this::assertTrue(true); + } + + public function testContactService(): void + { + $this->serviceBuilder->contact(); + $this::assertTrue(true); + } + + public function testDealProductRowsService(): void + { + $this->serviceBuilder->dealProductRows(); + $this::assertTrue(true); + } + + public function testDealCategoryStageService(): void + { + $this->serviceBuilder->dealCategoryStage(); + $this::assertTrue(true); + } + + protected function setUp(): void + { + $this->serviceBuilder = (new ServiceBuilder( + new NullCore(), + new NullBatch(), + new NullBulkItemsReader(), + new NullLogger() + ))->getCRMScope(); + } +} \ No newline at end of file diff --git a/tests/Unit/Services/IM/IMServiceBuilderTest.php b/tests/Unit/Services/IM/IMServiceBuilderTest.php new file mode 100644 index 00000000..7124e058 --- /dev/null +++ b/tests/Unit/Services/IM/IMServiceBuilderTest.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Services\IM; + +use Bitrix24\SDK\Services\IM\IMServiceBuilder; +use Bitrix24\SDK\Services\ServiceBuilder; +use Bitrix24\SDK\Tests\Unit\Stubs\NullBatch; +use Bitrix24\SDK\Tests\Unit\Stubs\NullBulkItemsReader; +use Bitrix24\SDK\Tests\Unit\Stubs\NullCore; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\TestCase; +use Psr\Log\NullLogger; + +#[CoversClass(IMServiceBuilder::class)] +class IMServiceBuilderTest extends TestCase +{ + private IMServiceBuilder $serviceBuilder; + + public function testGetIMService(): void + { + $this->serviceBuilder->notify(); + $this::assertTrue(true); + } + + protected function setUp(): void + { + $this->serviceBuilder = ( + new ServiceBuilder( + new NullCore(), + new NullBatch(), + new NullBulkItemsReader(), + new NullLogger() + ))->getIMScope(); + } +} \ No newline at end of file diff --git a/tests/Unit/Services/Main/MainServiceBuilderTest.php b/tests/Unit/Services/Main/MainServiceBuilderTest.php new file mode 100644 index 00000000..eb6487e4 --- /dev/null +++ b/tests/Unit/Services/Main/MainServiceBuilderTest.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Services\Main; + +use Bitrix24\SDK\Services\Main\MainServiceBuilder; +use Bitrix24\SDK\Services\ServiceBuilder; +use Bitrix24\SDK\Tests\Unit\Stubs\NullBatch; +use Bitrix24\SDK\Tests\Unit\Stubs\NullBulkItemsReader; +use Bitrix24\SDK\Tests\Unit\Stubs\NullCore; +use PHPUnit\Framework\TestCase; +use Psr\Log\NullLogger; + +/** + * Class CRMServiceBuilderTest + * + * @package Bitrix24\SDK\Tests\Unit\Services\CRM + */ +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\Main\MainServiceBuilder::class)] +class MainServiceBuilderTest extends TestCase +{ + private MainServiceBuilder $serviceBuilder; + + public function testGetMainService(): void + { + $this->serviceBuilder->main(); + $this::assertTrue(true); + } + + protected function setUp(): void + { + $this->serviceBuilder = (new ServiceBuilder( + new NullCore(), + new NullBatch(), + new NullBulkItemsReader(), + new NullLogger() + ))->getMainScope(); + } +} \ No newline at end of file diff --git a/tests/Unit/Services/ServiceBuilderTest.php b/tests/Unit/Services/ServiceBuilderTest.php new file mode 100644 index 00000000..698e1ec4 --- /dev/null +++ b/tests/Unit/Services/ServiceBuilderTest.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Services; + +use Bitrix24\SDK\Services\ServiceBuilder; +use Bitrix24\SDK\Tests\Unit\Stubs\NullBatch; +use Bitrix24\SDK\Tests\Unit\Stubs\NullBulkItemsReader; +use Bitrix24\SDK\Tests\Unit\Stubs\NullCore; +use PHPUnit\Framework\TestCase; +use Psr\Log\NullLogger; + +/** + * Class TestServiceBuilder + * + * @package Bitrix24\SDK\Tests\Unit\Services + */ +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\ServiceBuilder::class)] +class ServiceBuilderTest extends TestCase +{ + private ServiceBuilder $serviceBuilder; + + public function testGetMainScopeBuilder(): void + { + $this->serviceBuilder->getMainScope(); + $this::assertTrue(true); + } + + public function testGetIMScopeBuilder(): void + { + $this->serviceBuilder->getIMScope(); + $this::assertTrue(true); + } + + public function testGetCrmScopeBuilder(): void + { + $this->serviceBuilder->getCRMScope(); + $this::assertTrue(true); + } + + protected function setUp(): void + { + $this->serviceBuilder = new ServiceBuilder( + new NullCore(), + new NullBatch(), + new NullBulkItemsReader(), + new NullLogger() + ); + } +} \ No newline at end of file diff --git a/tests/Unit/Stubs/NullBatch.php b/tests/Unit/Stubs/NullBatch.php new file mode 100644 index 00000000..8b28d0c8 --- /dev/null +++ b/tests/Unit/Stubs/NullBatch.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Stubs; + +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +use Bitrix24\SDK\Core\Exceptions\BaseException; +use Bitrix24\SDK\Core\Response\DTO\Pagination; +use Bitrix24\SDK\Core\Response\DTO\ResponseData; +use Bitrix24\SDK\Core\Response\DTO\Time; +use Carbon\CarbonImmutable; +use Generator; + +class NullBatch implements BatchOperationsInterface +{ + + /** + * @inheritDoc + */ + public function getTraversableList(string $apiMethod, array $order, array $filter, array $select, ?int $limit = null, ?array $additionalParameters = null): Generator + { + yield []; + } + + /** + * @inheritDoc + */ + public function getTraversableListWithCount( + string $apiMethod, + array $order, + array $filter, + array $select, + ?int $limit = null + ): Generator { + yield []; + } + + /** + * @inheritDoc + */ + public function addEntityItems(string $apiMethod, array $entityItems): Generator + { + yield new ResponseData([],new Time(0,0,0,0,0, new CarbonImmutable(),new CarbonImmutable(),0,),new Pagination()); + } + + /** + * @inheritDoc + */ + public function deleteEntityItems(string $apiMethod, array $entityItemId): Generator + { + yield new ResponseData([],new Time(0,0,0,0,0, new CarbonImmutable(),new CarbonImmutable(),0,),new Pagination()); + } + + /** + * @inheritDoc + */ + public function updateEntityItems(string $apiMethod, array $entityItems): Generator + { + yield new ResponseData([],new Time(0,0,0,0,0, new CarbonImmutable(),new CarbonImmutable(),0,),new Pagination()); + } +} \ No newline at end of file diff --git a/tests/Unit/Stubs/NullBulkItemsReader.php b/tests/Unit/Stubs/NullBulkItemsReader.php new file mode 100644 index 00000000..5548be03 --- /dev/null +++ b/tests/Unit/Stubs/NullBulkItemsReader.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Stubs; + +use Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface; +use Generator; + +class NullBulkItemsReader implements BulkItemsReaderInterface +{ + /** + * @inheritDoc + */ + public function getTraversableList(string $apiMethod, array $order, array $filter, array $select, ?int $limit = null): Generator + { + yield []; + } +} \ No newline at end of file diff --git a/tests/Unit/Stubs/NullCore.php b/tests/Unit/Stubs/NullCore.php new file mode 100644 index 00000000..2e359926 --- /dev/null +++ b/tests/Unit/Stubs/NullCore.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tests\Unit\Stubs; + +use Bitrix24\SDK\Core\ApiClient; +use Bitrix24\SDK\Core\ApiLevelErrorHandler; +use Bitrix24\SDK\Core\Commands\Command; +use Bitrix24\SDK\Core\Contracts\ApiClientInterface; +use Bitrix24\SDK\Core\Contracts\CoreInterface; +use Bitrix24\SDK\Core\Credentials\Credentials; +use Bitrix24\SDK\Core\Credentials\WebhookUrl; +use Bitrix24\SDK\Core\Response\Response; +use Bitrix24\SDK\Infrastructure\HttpClient\RequestId\DefaultRequestIdGenerator; +use Psr\Log\NullLogger; +use Symfony\Component\HttpClient\MockHttpClient; +use Symfony\Component\HttpClient\Response\MockResponse; + +class NullCore implements CoreInterface +{ + /** + * + * @throws \Exception + */ + public function call(string $apiMethod, array $parameters = []): Response + { + return new Response(new MockResponse(''), new Command('', []), new ApiLevelErrorHandler(new NullLogger()), new NullLogger()); + } + + public function getApiClient(): ApiClientInterface + { + return new ApiClient( + Credentials::createFromWebhook(new WebhookUrl('')), + new MockHttpClient(), + new DefaultRequestIdGenerator(), + new NullLogger()); + } +} \ No newline at end of file diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 659a7d60..aad20729 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,11 +1,32 @@ + * © Maksim Mesilov * - * For the full copyright and license information, please view the LICENSE + * For the full copyright and license information, please view the MIT-LICENSE.txt * file that was distributed with this source code. */ -require __DIR__ . "/../vendor/autoload.php"; -date_default_timezone_set('UTC'); + +declare(strict_types=1); + +use Symfony\Component\Console\Input\ArgvInput; +use Symfony\Component\Dotenv\Dotenv; + +require_once dirname(__DIR__) . '/vendor/autoload.php'; + +if (!class_exists(Dotenv::class)) { + throw new LogicException('You need to add "symfony/dotenv" as Composer dependencies.'); +} + +$input = new ArgvInput(); +if (null !== $env = $input->getParameterOption(['--env', '-e'], null, true)) { + putenv('APP_ENV=' . $_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = $env); +} + +if ($input->hasParameterOption('--no-debug', true)) { + putenv('APP_DEBUG=' . $_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = '0'); +} + +(new Dotenv())->loadEnv(dirname(__DIR__) . '/tests/.env'); \ No newline at end of file diff --git a/tests/src/Bitrix24Test.php b/tests/src/Bitrix24Test.php deleted file mode 100644 index 5b1198d2..00000000 --- a/tests/src/Bitrix24Test.php +++ /dev/null @@ -1,125 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -namespace Bitrix24; - -use \Psr\Log\NullLogger; - -/** - * Class Bitrix24Test - * @package Bitrix24 - */ -class Bitrix24Test extends \PHPUnit_Framework_TestCase -{ - /** - * @covers Bitrix24::__construct - */ - public function testConstructorWithFirstArgumentIsNotBoolean() - { - $this->setExpectedException('\Bitrix24\Exceptions\Bitrix24Exception'); - $obBitrix24 = new Bitrix24(array()); - } - /** - * @covers Bitrix24::__construct - */ - public function testConstructorWithoutSecondArgument() - { - $obBitrix24 = new Bitrix24(false); - } - /** - * @covers Bitrix24::__construct - */ - public function testConstructorWithStubLogger() - { - $obBitrix24 = new Bitrix24(false, new NullLogger()); - } - /** - * @covers Bitrix24::setMemberId - */ - public function testSetMemberIdWithValidArgument() - { - $obBitrix24 = new Bitrix24(false, new NullLogger()); - $result = $obBitrix24->setMemberId('valid_member_id'); - $this->assertTrue($result); - } - /** - * @covers Bitrix24::setMemberId - */ - public function testSetMemberIdWithNullArgument() - { - $this->setExpectedException('\Bitrix24\Exceptions\Bitrix24Exception'); - $obBitrix24 = new Bitrix24(false, new NullLogger()); - $result = $obBitrix24->setMemberId(null); - $this->assertTrue($result); - } - /** - * @covers Bitrix24::setMemberId - */ - public function testSetMemberIdWithEmptyStringArgument() - { - $this->setExpectedException('\Bitrix24\Exceptions\Bitrix24Exception'); - $obBitrix24 = new Bitrix24(false, new NullLogger()); - $result = $obBitrix24->setMemberId(''); - $this->assertTrue($result); - } - /** - * @covers Bitrix24::setRetriesToConnectCount - */ - public function testSetRetriesToConnectCountWithNull() - { - $this->setExpectedException('\Bitrix24\Exceptions\Bitrix24Exception'); - $obBitrix24 = new Bitrix24(false, new NullLogger()); - $result = $obBitrix24->setRetriesToConnectCount(null); - } - /** - * @covers Bitrix24::setRetriesToConnectCount - */ - public function testSetRetriesToConnectCountWithEmptyArgs() - { - $obBitrix24 = new Bitrix24(false, new NullLogger()); - $result = $obBitrix24->setRetriesToConnectCount(); - $this->assertTrue($result); - } - /** - * @covers Bitrix24::setRetriesToConnectCount - */ - public function testSetRetriesToConnectCountWithValidArgs() - { - $obBitrix24 = new Bitrix24(false, new NullLogger()); - $result = $obBitrix24->setRetriesToConnectCount(1); - $this->assertTrue($result); - } - /** - * @covers Bitrix24::setRetriesToConnectTimeout - */ - public function testSetRetriesToConnectTimeoutWithNull() - { - $this->setExpectedException('\Bitrix24\Exceptions\Bitrix24Exception'); - $obBitrix24 = new Bitrix24(false, new NullLogger()); - $result = $obBitrix24->setRetriesToConnectTimeout(null); - } - /** - * @covers Bitrix24::setRetriesToConnectTimeout - */ - public function testSetRetriesToConnectTimeoutWithEmptyArgs() - { - $obBitrix24 = new Bitrix24(false, new NullLogger()); - $result = $obBitrix24->setRetriesToConnectTimeout(); - $this->assertTrue($result); - } - /** - * @covers Bitrix24::setRetriesToConnectTimeout - */ - public function testSetRetriesToConnectTimeoutWithValidArgs() - { - $obBitrix24 = new Bitrix24(false, new NullLogger()); - $result = $obBitrix24->setRetriesToConnectTimeout(1000000); - $this->assertTrue($result); - } -} \ No newline at end of file diff --git a/tests/src/classes/im/attach/attachTest.php b/tests/src/classes/im/attach/attachTest.php deleted file mode 100644 index 8e947072..00000000 --- a/tests/src/classes/im/attach/attachTest.php +++ /dev/null @@ -1,74 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24; - -use \Bitrix24\Im\Attach\Attach; -use \Psr\Log\NullLogger; - -/** - * Class AttachTest - * @package Bitrix24 - */ -class AttachTest extends \PHPUnit_Framework_TestCase -{ - /** - * @covers \Bitrix24\Im\Attach\Attach::__construct - */ - public function testAttachConstructWithNullArguments() - { - $obItem = new Attach(null, null); - } - - /** - * @covers \Bitrix24\Im\Attach\Attach::setStatusNormal - */ - public function testAttachSetStatusNormal() - { - $obItem = new Attach(null, null); - $obItem->setStatusNormal(); - } - - /** - * @covers \Bitrix24\Im\Attach\Attach::setStatusAttention - */ - public function testAttachSetStatusAttention() - { - $obItem = new Attach(null, null); - $obItem->setStatusAttention(); - } - - /** - * @covers \Bitrix24\Im\Attach\Attach::setStatusProblem - */ - public function testAttachSetStatusProblem() - { - $obItem = new Attach(null, null); - $obItem->setStatusProblem(); - } - - /** - * @covers \Bitrix24\Im\Attach\Attach::getData - */ - public function testAttachGetData() - { - $obItem = new Attach(null, null); - $obItem->getData(); - } - - /** - * @covers \Bitrix24\Im\Attach\Attach::getAttachItems - */ - public function testAttachGetAttachItems() - { - $obItem = new Attach(null, null); - $obItem->getAttachItems(); - } -} \ No newline at end of file diff --git a/tests/src/classes/im/attach/item/delimiterTest.php b/tests/src/classes/im/attach/item/delimiterTest.php deleted file mode 100644 index 50ab0e10..00000000 --- a/tests/src/classes/im/attach/item/delimiterTest.php +++ /dev/null @@ -1,30 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24; - -use \Bitrix24\Im\Attach\Item\Delimiter; -use \Psr\Log\NullLogger; - -/** - * Class DelimiterTest - * @package Bitrix24 - */ -class DelimiterTest extends \PHPUnit_Framework_TestCase -{ - /** - * @covers \Bitrix24\Im\Attach\Item\Delimiter::getAttachTypeCode - */ - public function testDelimiterTypeCode() - { - $obItem = new Delimiter(); - $this->assertSame($obItem->getAttachTypeCode(), 'DELIMITER'); - } -} \ No newline at end of file diff --git a/tests/src/classes/im/attach/item/fileTest.php b/tests/src/classes/im/attach/item/fileTest.php deleted file mode 100644 index ae443591..00000000 --- a/tests/src/classes/im/attach/item/fileTest.php +++ /dev/null @@ -1,30 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24; - -use \Bitrix24\Im\Attach\Item\File; -use \Psr\Log\NullLogger; - -/** - * Class FileTest - * @package Bitrix24 - */ -class FileTest extends \PHPUnit_Framework_TestCase -{ - /** - * @covers \Bitrix24\Im\Attach\Item\File::getAttachTypeCode - */ - public function testFileTypeCode() - { - $obItem = new File(null, null, null); - $this->assertSame($obItem->getAttachTypeCode(), 'FILE'); - } -} \ No newline at end of file diff --git a/tests/src/classes/im/attach/item/gridTest.php b/tests/src/classes/im/attach/item/gridTest.php deleted file mode 100644 index 8d073740..00000000 --- a/tests/src/classes/im/attach/item/gridTest.php +++ /dev/null @@ -1,30 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24; - -use \Bitrix24\Im\Attach\Item\Grid; -use \Psr\Log\NullLogger; - -/** - * Class GridTest - * @package Bitrix24 - */ -class GridTest extends \PHPUnit_Framework_TestCase -{ - /** - * @covers \Bitrix24\Im\Attach\Item\Grid::getAttachTypeCode - */ - public function testGridTypeCode() - { - $obItem = new Grid(); - $this->assertSame($obItem->getAttachTypeCode(), 'GRID'); - } -} \ No newline at end of file diff --git a/tests/src/classes/im/attach/item/imageTest.php b/tests/src/classes/im/attach/item/imageTest.php deleted file mode 100644 index 94174095..00000000 --- a/tests/src/classes/im/attach/item/imageTest.php +++ /dev/null @@ -1,30 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24; - -use \Bitrix24\Im\Attach\Item\Image; -use \Psr\Log\NullLogger; - -/** - * Class ImageTest - * @package Bitrix24 - */ -class ImageTest extends \PHPUnit_Framework_TestCase -{ - /** - * @covers \Bitrix24\Im\Attach\Item\Image::getAttachTypeCode - */ - public function testImageTypeCode() - { - $obItem = new Image(null, null); - $this->assertSame($obItem->getAttachTypeCode(), 'IMAGE'); - } -} \ No newline at end of file diff --git a/tests/src/classes/im/attach/item/linkTest.php b/tests/src/classes/im/attach/item/linkTest.php deleted file mode 100644 index 8b021815..00000000 --- a/tests/src/classes/im/attach/item/linkTest.php +++ /dev/null @@ -1,30 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24; - -use \Bitrix24\Im\Attach\Item\Link; -use \Psr\Log\NullLogger; - -/** - * Class LinkTest - * @package Bitrix24 - */ -class LinkTest extends \PHPUnit_Framework_TestCase -{ - /** - * @covers \Bitrix24\Im\Attach\Item\Link::getAttachTypeCode - */ - public function testLinkTypeCode() - { - $obItem = new Link(null, null, null, null); - $this->assertSame($obItem->getAttachTypeCode(), 'LINK'); - } -} \ No newline at end of file diff --git a/tests/src/classes/im/attach/item/messageTest.php b/tests/src/classes/im/attach/item/messageTest.php deleted file mode 100644 index 1693eefd..00000000 --- a/tests/src/classes/im/attach/item/messageTest.php +++ /dev/null @@ -1,30 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24; - -use \Bitrix24\Im\Attach\Item\Message; -use \Psr\Log\NullLogger; - -/** - * Class MessageTest - * @package Bitrix24 - */ -class MessageTest extends \PHPUnit_Framework_TestCase -{ - /** - * @covers \Bitrix24\Im\Attach\Item\Message::getAttachTypeCode - */ - public function testUserListWithNullArgument() - { - $obItem = new Message('Test message'); - $this->assertSame($obItem->getAttachTypeCode(), 'MESSAGE'); - } -} \ No newline at end of file diff --git a/tests/src/classes/im/attach/item/userTest.php b/tests/src/classes/im/attach/item/userTest.php deleted file mode 100644 index 72999dc6..00000000 --- a/tests/src/classes/im/attach/item/userTest.php +++ /dev/null @@ -1,30 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24; - -use \Bitrix24\Im\Attach\Item\User; -use \Psr\Log\NullLogger; - -/** - * Class UserTest - * @package Bitrix24 - */ -class UserTest extends \PHPUnit_Framework_TestCase -{ - /** - * @covers \Bitrix24\Im\Attach\Item\User::getAttachTypeCode - */ - public function testUserTypeCode() - { - $obItem = new User(null); - $this->assertSame($obItem->getAttachTypeCode(), 'USER'); - } -} \ No newline at end of file diff --git a/tests/src/classes/im/chatTest.php b/tests/src/classes/im/chatTest.php deleted file mode 100644 index c6f8f4cf..00000000 --- a/tests/src/classes/im/chatTest.php +++ /dev/null @@ -1,268 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24; - -use \Bitrix24\Im\Chat; -use \Bitrix24\Contracts\iBitrix24; -use \Bitrix24\Stub\Bitrix24 as Bitrix24NullObject; - -use \Psr\Log\NullLogger; - -/** - * Class ChatTest - * @package Bitrix24 - */ -class ChatTest extends \PHPUnit_Framework_TestCase -{ - /** - * @var iBitrix24 - */ - protected $bitrix24App; - - /** - * @var int - */ - protected $defaultChatId; - - /** - * @return void - */ - protected function setUp() - { - $this->bitrix24App = new Bitrix24NullObject(); - $this->defaultChatId = 1; - } - - /** - * @covers \Bitrix24\Im\Chat::userList - */ - public function testUserListWithNullArgument() - { - $obChat = new Chat($this->bitrix24App); - $obChat->userList(null); - } - - /** - * @covers \Bitrix24\Im\Chat::userList - */ - public function testUserListWithNumericArgument() - { - $obChat = new Chat($this->bitrix24App); - $obChat->userList($this->defaultChatId); - } - - /** - * @covers \Bitrix24\Im\Chat::add - */ - public function testAddChatWithTitleAndDescription() - { - $obChat = new Chat($this->bitrix24App); - $obChat->add('chat title', 'chat description'); - } - - /** - * @covers \Bitrix24\Im\Chat::delete - */ - public function testDeleteWithNullArgument() - { - $obChat = new Chat($this->bitrix24App); - $obChat->delete(null); - } - - /** - * @covers \Bitrix24\Im\Chat::delete - */ - public function testDeleteWithNumericArgument() - { - $obChat = new Chat($this->bitrix24App); - $obChat->delete($this->defaultChatId); - } - - /** - * @covers \Bitrix24\Im\Chat::setOwner - */ - public function testSetOwnerWithNullChatId() - { - $obChat = new Chat($this->bitrix24App); - $obChat->setOwner(null, $this->defaultChatId); - } - - /** - * @covers \Bitrix24\Im\Chat::setOwner - */ - public function testSetOwnerWithNullUserId() - { - $obChat = new Chat($this->bitrix24App); - $obChat->setOwner($this->defaultChatId, null); - } - - /** - * @covers \Bitrix24\Im\Chat::setOwner - */ - public function testSetOwnerWithValidArguments() - { - $obChat = new Chat($this->bitrix24App); - $obChat->setOwner($this->defaultChatId, 1); - } - - /** - * @covers \Bitrix24\Im\Chat::updateColor - */ - public function testUpdateColorWithValidArguments() - { - $obChat = new Chat($this->bitrix24App); - $obChat->updateColor($this->defaultChatId, 'RED'); - } - - /** - * @covers \Bitrix24\Im\Chat::updateColor - */ - public function testUpdateColorWithNullChatId() - { - $obChat = new Chat($this->bitrix24App); - $obChat->updateColor(null, 'RED'); - } - - /** - * @covers \Bitrix24\Im\Chat::updateColor - */ - public function testUpdateColorWithNullColor() - { - $obChat = new Chat($this->bitrix24App); - $obChat->updateColor($this->defaultChatId, null); - } - - /** - * @covers \Bitrix24\Im\Chat::updateTitle - */ - public function testUpdateTitleWithValidArguments() - { - $obChat = new Chat($this->bitrix24App); - $obChat->updateTitle($this->defaultChatId, 'test title'); - } - - /** - * @covers \Bitrix24\Im\Chat::updateTitle - */ - public function testUpdateTitleWithNullChatId() - { - $obChat = new Chat($this->bitrix24App); - $obChat->updateTitle(null, 'test title'); - } - - /** - * @covers \Bitrix24\Im\Chat::updateTitle - */ - public function testUpdateTitleWithNullTitle() - { - $obChat = new Chat($this->bitrix24App); - $obChat->updateTitle($this->defaultChatId, null); - } - - /** - * @covers \Bitrix24\Im\Chat::updateAvatar - */ - public function testUpdateAvatarWithValidArguments() - { - $obChat = new Chat($this->bitrix24App); - $obChat->updateAvatar($this->defaultChatId, 'test avatar'); - } - - /** - * @covers \Bitrix24\Im\Chat::updateAvatar - */ - public function testUpdateAvatarWithNullChatId() - { - $obChat = new Chat($this->bitrix24App); - $obChat->updateAvatar(null, 'test avatar'); - } - - /** - * @covers \Bitrix24\Im\Chat::updateAvatar - */ - public function testUpdateAvatarWithNullAvatar() - { - $obChat = new Chat($this->bitrix24App); - $obChat->updateAvatar($this->defaultChatId, null); - } - - /** - * @covers \Bitrix24\Im\Chat::sendTyping - */ - public function testSendTypingWithValidArguments() - { - $obChat = new Chat($this->bitrix24App); - $obChat->sendTyping($this->defaultChatId); - } - - /** - * @covers \Bitrix24\Im\Chat::sendTyping - */ - public function testSendTypingWithNullChatId() - { - $obChat = new Chat($this->bitrix24App); - $obChat->sendTyping(null); - } - - /** - * @covers \Bitrix24\Im\Chat::userDelete - */ - public function testUserDeleteWithValidArguments() - { - $obChat = new Chat($this->bitrix24App); - $obChat->userDelete($this->defaultChatId, 1); - } - - /** - * @covers \Bitrix24\Im\Chat::userDelete - */ - public function testUserDeleteWithNullChatId() - { - $obChat = new Chat($this->bitrix24App); - $obChat->userDelete(null, 1); - } - - /** - * @covers \Bitrix24\Im\Chat::userDelete - */ - public function testUserDeleteWithNullUserId() - { - $obChat = new Chat($this->bitrix24App); - $obChat->userDelete($this->defaultChatId, null); - } - - /** - * @covers \Bitrix24\Im\Chat::userAdd - */ - public function testUserAddWithValidArguments() - { - $obChat = new Chat($this->bitrix24App); - $obChat->userAdd($this->defaultChatId, array(2, 3, 4)); - } - - /** - * @covers \Bitrix24\Im\Chat::userAdd - */ - public function testUserAddWithNullChatId() - { - $obChat = new Chat($this->bitrix24App); - $obChat->userAdd(null, array(2, 3, 4)); - } - - /** - * @covers \Bitrix24\Im\Chat::userAdd - */ - public function testUserAddWithEmptyArray() - { - $obChat = new Chat($this->bitrix24App); - $obChat->userAdd($this->defaultChatId, array()); - } -} \ No newline at end of file diff --git a/tools/.env b/tools/.env new file mode 100644 index 00000000..635adce5 --- /dev/null +++ b/tools/.env @@ -0,0 +1,3 @@ +APP_ENV=dev +LOGS_FILE=tools/logs/cli.log +LOGS_LEVEL=300 \ No newline at end of file diff --git a/tools/Commands/CopyPropertyValues.php b/tools/Commands/CopyPropertyValues.php new file mode 100644 index 00000000..4c2bfd1c --- /dev/null +++ b/tools/Commands/CopyPropertyValues.php @@ -0,0 +1,305 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tools\Commands; + +use Bitrix24\SDK\Services\CRM\Contact\Service\Contact; +use Bitrix24\SDK\Services\ServiceBuilderFactory; +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Command\Command; +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 Psr\Log\LoggerInterface; + +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; +use Symfony\Component\Console\Helper\ProgressBar; + + +#[AsCommand( + name: 'b24:etl:copy-property-values', + description: 'copy property values from one property to another', + hidden: false +)] +class CopyPropertyValues extends Command +{ + protected LoggerInterface $logger; + protected const WEBHOOK_URL = 'webhook'; + protected const SOURCE_PROPERTY = 'source'; + protected const DESTINATION_PROPERTY = 'destination'; + protected const ENTITY_TYPE_PROPERTY = 'entity_type'; + private array $supportedEntityTypes = [ + 'contact', + 'company', + 'lead', + 'deal', + ]; + + public function __construct(LoggerInterface $logger) + { + // best practices recommend to call the parent constructor first and + // then set your own properties. That wouldn't work in this case + // because configure() needs the properties set in this constructor + $this->logger = $logger; + parent::__construct(); + } + + /** + * @param OutputInterface $output + * @param Contact $service + * @param array $updateCmd + * @return void + * @throws BaseException + */ + public function updateItems(OutputInterface $output, Contact $service, array $updateCmd): void + { + $progressBar = new ProgressBar($output, count($updateCmd)); + $progressBar->start(); + + foreach ($service->batch->update($updateCmd) as $item) { + $this->logger->debug('updateItems', [ + 'isUpdated' => $item->isSuccess() === true ? 'Y' : 'N', + ]); + $progressBar->advance(); + } + + $progressBar->finish(); + } + + + public function createUpdateCommand(array $data, string $b24SourceProp, string $b24DestinationProp): array + { + $updateCmd = []; + foreach ($data as $id => $item) { + $updateCmd[$id] = [ + 'fields' => [ + $b24DestinationProp =>$item[$b24SourceProp], + ] + ]; + } + + return $updateCmd; + } + + /** + * @param OutputInterface $output + * @param Contact $service + * @param array $filter + * @param string $b24SourceProp + * @param string $b24DestinationProp + * @return array + * @throws BaseException + * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws \Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNotFoundException + */ + public function readDataFromProperties(OutputInterface $output, Contact $service, array $filter, string $b24SourceProp, string $b24DestinationProp): array + { + $progressBar = new ProgressBar($output, $service->countByFilter($filter)); + $progressBar->start(); + + $data = []; + foreach ($service->batch->list([], $filter, ['ID', $b24SourceProp, $b24DestinationProp]) as $id => $item) { + $data[$item->ID] = [ + $b24SourceProp => (string)$item->getUserfieldByFieldName($b24SourceProp), + $b24DestinationProp => (string)$item->getUserfieldByFieldName($b24DestinationProp), + ]; + $progressBar->advance(); + } + $progressBar->finish(); + + return $data; + } + + protected function configure(): void + { + $this + ->setDescription('copy property values from one property to another') + ->setHelp('copy property values from one property to another in same portal') + ->addOption( + self::WEBHOOK_URL, + null, + InputOption::VALUE_REQUIRED, + 'bitrix24 incoming webhook', + '' + ) + ->addOption( + self::SOURCE_PROPERTY, + null, + InputOption::VALUE_REQUIRED, + 'source property id', + + ) + ->addOption( + self::DESTINATION_PROPERTY, + null, + InputOption::VALUE_REQUIRED, + 'destination property id', + ) + ->addOption( + self::ENTITY_TYPE_PROPERTY, + null, + InputOption::VALUE_REQUIRED, + 'entity type: contact, company, lead, deal', + ); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $this->logger->debug('CopyPropertyValues.start'); + + $b24Webhook = (string)$input->getOption(self::WEBHOOK_URL); + $b24EntityType = (string)$input->getOption(self::ENTITY_TYPE_PROPERTY); + $b24SourceProp = (string)$input->getOption(self::SOURCE_PROPERTY); + $b24DestinationProp = (string)$input->getOption(self::DESTINATION_PROPERTY); + + $io = new SymfonyStyle($input, $output); + $output->writeln( + [ + 'Copy property values from one property to another', + '========================', + sprintf('webhook url: %s', $b24Webhook), + sprintf('entity type: %s', $b24EntityType), + sprintf('source property: %s', $b24SourceProp), + sprintf('destination property: %s', $b24DestinationProp), + ] + ); + + try { + if ($b24Webhook === '') { + throw new InvalidArgumentException('webhook url is empty'); + } + if ($b24EntityType === '') { + throw new InvalidArgumentException('entity_type is empty'); + } + if ($b24SourceProp === '') { + throw new InvalidArgumentException('source property is empty'); + } + if ($b24DestinationProp === '') { + throw new InvalidArgumentException('destination property is empty'); + } + $sb = (new ServiceBuilderFactory(new EventDispatcher(), $this->logger))->initFromWebhook($b24Webhook); + if (!in_array($b24EntityType, $this->supportedEntityTypes, true)) { + throw new InvalidArgumentException(sprintf('entity type %s is not supported', $b24EntityType)); + } + + $service = null; + switch ($b24EntityType) { + case 'contact': + $fields = $sb->getCRMScope()->contact()->fields(); + $service = $sb->getCRMScope()->contact(); + break; + case 'company': + case 'lead': + case 'deal': + default: + throw new InvalidArgumentException(sprintf('unsupported entity type %s', $b24EntityType)); + } + + if (!array_key_exists($b24SourceProp, $fields->getFieldsDescription())) { + throw new InvalidArgumentException(sprintf('source property «%s» is not found in entity %s', $b24SourceProp, $b24EntityType)); + } + if (!array_key_exists($b24DestinationProp, $fields->getFieldsDescription())) { + throw new InvalidArgumentException(sprintf('destination property «%s» is not found in entity %s', $b24DestinationProp, $b24EntityType)); + } + + // количество элементов c заполненным полем источником + // количество элементов с заполненным полем назначения + // количество элементов у которых заполнено ОБА поля + $totalElementsCnt = $service->countByFilter(); + $elementsWithFilledSourceProp = $service->countByFilter([sprintf('!%s', $b24SourceProp) => null]); + $elementsWithoutFilledSourceProp = $service->countByFilter([sprintf('%s', $b24SourceProp) => null]); + $elementsWithFilledDestinationProp = $service->countByFilter([sprintf('!%s', $b24DestinationProp) => null]); + $elementsWithoutFilledDestinationProp = $service->countByFilter([sprintf('%s', $b24DestinationProp) => null]); + + $io->info( + [ + '', + sprintf('total elements count: %s ', $totalElementsCnt), + sprintf('elements with filled source property: %s ', $elementsWithFilledSourceProp), + sprintf('elements without filled source property: %s ', $elementsWithoutFilledSourceProp), + sprintf('elements with filled destination property: %s ', $elementsWithFilledDestinationProp), + sprintf('elements without filled destination property: %s ', $elementsWithoutFilledDestinationProp) + ] + ); + $io->info('read data from bitrix24...'); + // read data from source and destinations properties + $dataFromProperties = $this->readDataFromProperties($output, $service, [ + sprintf('!%s', $b24SourceProp) => '' + ], $b24SourceProp, $b24DestinationProp); + + // exclude items with filled destination property + $dataToCopy = []; + $conflictData = []; + foreach ($dataFromProperties as $id => $item) { + // pass items with copied values + if ($item[$b24SourceProp] === $item[$b24DestinationProp]) { + continue; + } + + // filter conflict items + if($item[$b24DestinationProp] !== '') { + $conflictData[$id] = $item; + } + // filter items to copy + if($item[$b24DestinationProp] === '') { + $dataToCopy[$id] = $item; + } + } + $io->newLine(); + $io->warning([ + '', + sprintf('conflict items count: %s', count($conflictData)), + sprintf('problem id: %s', implode(', ', array_keys($conflictData))), + ]); + + $io->info([ + '', + sprintf('items to copy count: %s', count($dataToCopy)) + ]); + + // build update command + $updateCmd = $this->createUpdateCommand($dataToCopy, $b24SourceProp, $b24DestinationProp); + + // update items + $this->updateItems($output, $service, $updateCmd); + + $io->success('all items updated'); + } catch (BaseException $exception) { + $io = new SymfonyStyle($input, $output); + $io->caution(sprintf('error message: %s', $exception->getMessage())); + $io->text( + $exception->getTraceAsString() + ); + } catch (\Throwable $exception) { + $io = new SymfonyStyle($input, $output); + $io->caution('unknown error'); + $io->text( + [ + sprintf('%s', $exception->getMessage()), + ] + ); + } + $this->logger->debug('CopyPropertyValues.finish'); + + return Command::SUCCESS; + } +} \ No newline at end of file diff --git a/tools/Commands/GenerateContactsCommand.php b/tools/Commands/GenerateContactsCommand.php new file mode 100644 index 00000000..0c77721c --- /dev/null +++ b/tools/Commands/GenerateContactsCommand.php @@ -0,0 +1,219 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tools\Commands; + +use Symfony\Component\Console\Attribute\AsCommand; +use Symfony\Component\Console\Command\Command; +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; +use Psr\Log\LoggerInterface; + +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; + +#[AsCommand( + name: 'b24:generate:contacts', + description: 'generate demo-data contacts in CRM', + hidden: false +)] +class GenerateContactsCommand extends Command +{ + /** + * @var LoggerInterface + */ + protected LoggerInterface $logger; + protected const CONTACTS_COUNT = 'count'; + protected const WEBHOOK_URL = 'webhook'; + + /** + * GenerateContactsCommand constructor. + * + * @param LoggerInterface $logger + */ + public function __construct(LoggerInterface $logger) + { + // best practices recommend to call the parent constructor first and + // then set your own properties. That wouldn't work in this case + // because configure() needs the properties set in this constructor + $this->logger = $logger; + parent::__construct(); + } + + /** + * настройки + */ + protected function configure(): void + { + $this + ->setDescription('generate contacts') + ->setHelp('generate demo-data contacts in CRM') + ->addOption( + self::WEBHOOK_URL, + null, + InputOption::VALUE_REQUIRED, + 'bitrix24 incoming webhook', + '' + ) + ->addOption( + self::CONTACTS_COUNT, + null, + InputOption::VALUE_REQUIRED, + 'contacts count', + 1 + ); + } + + /** + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param \Symfony\Component\Console\Output\OutputInterface $output + * + * @return void + */ + protected function interact(InputInterface $input, OutputInterface $output): void + { + $b24Webhook = (string)$input->getOption(self::WEBHOOK_URL); + if ($b24Webhook === '') { + throw new InvalidArgumentException(sprintf('option %s not found, you must set this option', self::WEBHOOK_URL)); + } + } + + /** + * @param InputInterface $input + * @param OutputInterface $output + * + * @return int + */ + protected function execute(InputInterface $input, OutputInterface $output): int + { + $this->logger->debug('GenerateContactsCommand.start'); + + $contactsCount = (int)$input->getOption(self::CONTACTS_COUNT); + $b24Webhook = (string)$input->getOption(self::WEBHOOK_URL); + $io = new SymfonyStyle($input, $output); + + $output->writeln( + [ + 'Generate contacts in CRM', + '========================', + sprintf('webhook url: %s', $b24Webhook), + sprintf('try to add contacts: %s', $contactsCount), + ] + ); + + try { + // todo create service builder factory + $core = (new CoreBuilder()) + ->withLogger($this->logger) + ->withCredentials(Credentials::createFromWebhook(new WebhookUrl($b24Webhook))) + ->build(); + $batch = new Batch( + $core, + $this->logger + ); + $services = new ServiceBuilder( + $core, + $batch, + (new BulkItemsReaderBuilder( + $core, + $batch, + $this->logger + )) + ->build(), + $this->logger + ); + + $output->writeln(sprintf('contacts total count: %s', $services->getCRMScope()->contact()->countByFilter())); + + $io->section('start adding contacts…'); + $timeStart = microtime(true); + foreach ( + $services->getCRMScope()->contact()->batch->add( + $this->generateContacts($contactsCount) + ) as $queryCnt => $addedItem + ) { + /** + * @var $queryResultData \Bitrix24\SDK\Core\Result\AddedItemBatchResult + */ + $io->writeln( + [ + sprintf( + '%s Mb |%s of %s | contact id: %s', + round(memory_get_peak_usage(true) / 1024 / 1024, 2), + $queryCnt + 1, + $contactsCount, + $addedItem->getId() + ), + ] + ); + } + $timeEnd = microtime(true); + $io->writeln(sprintf('batch query duration: %s seconds', round($timeEnd - $timeStart, 2)) . PHP_EOL . PHP_EOL); + $io->success('contacts added'); + } catch (BaseException $exception) { + $io = new SymfonyStyle($input, $output); + $io->caution(sprintf('error message: %s', $exception->getMessage())); + $io->text( + $exception->getTraceAsString() + ); + } catch (\Throwable $exception) { + $io = new SymfonyStyle($input, $output); + $io->caution('unknown error'); + $io->text( + [ + sprintf('%s', $exception->getMessage()), + ] + ); + } + $this->logger->debug('GenerateContactsCommand.finish'); + + return Command::SUCCESS; + } + + /** + * Generate fake contacts + * + * @param int $contactsCount + * + * @return array $contacts + * @throws \Exception + */ + protected function generateContacts(int $contactsCount): array + { + $contacts = []; + for ($i = 0; $i < $contactsCount; $i++) { + $contacts[] = [ + 'NAME' => sprintf('name_%s', $i), + 'LAST_NAME' => sprintf('last_%s', $i), + 'SECOND_NAME' => sprintf('second_%s', $i), + 'PHONE' => [ + ['VALUE' => sprintf('+7978%s', random_int(1000000, 9999999)), 'VALUE_TYPE' => 'MOBILE'], + ], + 'EMAIL' => [ + ['VALUE' => sprintf('test-%s@gmail.com', random_int(1000000, 9999999)), 'VALUE_TYPE' => 'WORK'], + ], + ]; + } + + return $contacts; + } +} + diff --git a/tools/Commands/PerformanceBenchmarks/ListCommand.php b/tools/Commands/PerformanceBenchmarks/ListCommand.php new file mode 100644 index 00000000..7a2a70d2 --- /dev/null +++ b/tools/Commands/PerformanceBenchmarks/ListCommand.php @@ -0,0 +1,444 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tools\Commands\PerformanceBenchmarks; + +use Bitrix24\SDK\Core\Batch; +use Bitrix24\SDK\Core\Contracts\BatchOperationsInterface; +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; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Helper\ProgressBar; +use Symfony\Component\Console\Helper\Table; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Component\Console\Attribute\AsCommand; + + +#[AsCommand( + name: 'b24:benchmark:list', + description: 'performance benchmark for *.list method', + hidden: false +)] +class ListCommand extends Command +{ + protected LoggerInterface $logger; + protected CoreInterface $core; + protected BatchOperationsInterface $batch; + protected const TIME_PRECISION = 4; + protected const SELECT_FIELDS_MODE = 'fields'; + protected const ELEMENTS_COUNT = 'count'; + protected const WEBHOOK_URL = 'webhook'; + protected const ROUNDS_COUNT = 'rounds'; + protected array $benchmarkItems = [ + 'order_count' => '1. ordered, count total elements', + 'order_without_count' => '2. ordered, without count total elements', + 'without_order_count' => '3. default order, count total elements', + 'without_order_without_count' => '4. default order, without count total elements', + ]; + protected array $selectMode = [ + 'partial' => ['ID', 'NAME', 'LAST_NAME', 'DATE_CREATE', 'PHONE', 'EMAIL'], + 'system' => ['*', 'PHONE', 'EMAIL', 'IM'], + 'all' => ['*', 'PHONE', 'EMAIL', 'IM', 'UF_*'], + ]; + + /** + * ListCommand constructor. + * + * @param LoggerInterface $logger + */ + public function __construct(LoggerInterface $logger) + { + // best practices recommend to call the parent constructor first and + // then set your own properties. That wouldn't work in this case + // because configure() needs the properties set in this constructor + $this->logger = $logger; + parent::__construct(); + } + + /** + * настройки + */ + protected function configure(): void + { + $this + ->setDescription('performance benchmark for *.list method') + ->setHelp('performance benchmark for *.list method with simple or batch mode if need read more than 50 elements') + ->addOption( + self::WEBHOOK_URL, + null, + InputOption::VALUE_REQUIRED, + 'bitrix24 incoming webhook', + '' + ) + ->addOption( + self::ROUNDS_COUNT, + null, + InputOption::VALUE_REQUIRED, + 'benchmark rounds count', + 3 + ) + ->addOption( + self::SELECT_FIELDS_MODE, + null, + InputOption::VALUE_REQUIRED, + 'select fields mode (partial | system | all)', + 'all' + ) + ->addOption( + self::ELEMENTS_COUNT, + null, + InputOption::VALUE_REQUIRED, + 'read elements count', + 50 + ); + } + + /** + * @param InputInterface $input + * @param OutputInterface $output + * + * @return int + */ + protected function execute(InputInterface $input, OutputInterface $output): int + { + $this->logger->debug('ListCommand.start'); + + $b24Webhook = (string)$input->getOption(self::WEBHOOK_URL); + $selectFieldsMode = strtolower((string)$input->getOption(self::SELECT_FIELDS_MODE)); + $elementsCount = (int)$input->getOption(self::ELEMENTS_COUNT); + $roundsCount = (int)$input->getOption(self::ROUNDS_COUNT); + + $isUseBatchMode = false; + if ($elementsCount > 50) { + $isUseBatchMode = true; + } + + $io = new SymfonyStyle($input, $output); + try { + $output->writeln( + [ + 'PerformanceBenchmark for crm.contact.list method', + '================================================', + sprintf('webhook url: %s', $b24Webhook), + sprintf('elements count: %s', $elementsCount), + sprintf('is use batch read mode: %s', $isUseBatchMode ? 'yes' : 'no'), + sprintf('benchmark rounds count: %s', $roundsCount), + sprintf('select fields mode: %s', $selectFieldsMode), + '', + 'fields select modes:', + '- partial: ID, NAME, LAST_NAME, DATE_CREATE, PHONE, EMAIL, IM', + '- system: *, PHONE, EMAIL, IM', + '- all: *, PHONE, EMAIL, IM, UF_*', + ] + ); + + $this->core = (new CoreBuilder()) + ->withLogger($this->logger) + ->withCredentials(Credentials::createFromWebhook(new WebhookUrl($b24Webhook))) + ->build(); + $this->batch = new Batch( + $this->core, + $this->logger + ); + + $countResult = $this->core->call('crm.contact.list'); + $output->writeln(['======', '']); + $output->writeln(sprintf('contacts total count: %s', $countResult->getResponseData()->getPagination()->getTotal())); + + + $order = ['DATE_CREATE' => 'ASC']; + $filter = ['>ID' => 1]; + if (!array_key_exists($selectFieldsMode, $this->selectMode)) { + throw new \InvalidArgumentException(sprintf('invalid select mode %s', $selectFieldsMode)); + } + $select = $this->selectMode[$selectFieldsMode]; + + + if ($isUseBatchMode) { + $output->writeln(sprintf('crm.contact.list - get %s elements in batch mode...', $elementsCount)); + + $result = $this->batchList($output, $order, $filter, $select, $elementsCount); + + $output->writeln(''); + $table = new Table($output); + $table->setHeaders(['Mode', 'Time']); + $table->addRow([$this->benchmarkItems['order_count'], round($result['order_count'], self::TIME_PRECISION)]); + $table->addRow([$this->benchmarkItems['order_without_count'], round($result['order_without_count'], self::TIME_PRECISION)]); + $table->addRow([$this->benchmarkItems['without_order_count'], round($result['without_order_count'], self::TIME_PRECISION)]); + $table->addRow( + [ + $this->benchmarkItems['without_order_without_count'], + round($result['without_order_without_count'], self::TIME_PRECISION), + ] + ); + $table->render(); + } else { + $output->writeln('crm.contact.list - get first 50 elements...'); + + // creates a new progress bar (50 units) + $progressBar = new ProgressBar($output, $roundsCount); + $progressBar->start(); + + $totalStat = []; + for ($i = 0; $i < $roundsCount; $i++) { + $totalStat[] = $this->simpleList($order, $filter, $select); + $progressBar->advance(); + } + $progressBar->finish(); + $output->writeln(''); + $table = new Table($output); + $table + ->setHeaders(['Mode', 'Time']); + foreach ($this->benchmarkItems as $code => $description) { + // calculate average + $roundsStat = array_column($totalStat, $code); + $value = round(array_sum($roundsStat) / count($roundsStat), self::TIME_PRECISION); + $table->addRow( + [ + $this->benchmarkItems[$code], + $value, + ] + ); + } + $table->render(); + } + $io->success('benchmark finished'); + } catch (BaseException $exception) { + $io->caution('Bitrix24 error'); + $io->text( + [ + sprintf('%s', $exception->getMessage()), + ] + ); + } catch (\Throwable $exception) { + $io->caution('fatal error'); + $io->text( + [ + $exception->getMessage(), + $exception->getTraceAsString(), + ] + ); + } + $this->logger->debug('ListCommand.start.finish'); + + return self::SUCCESS; + } + + /** + * @param OutputInterface $output + * @param array $order + * @param array $filter + * @param array $select + * @param int $elementsCount + * + * @return array + * @throws BaseException + * @throws ClientExceptionInterface + * @throws RedirectionExceptionInterface + * @throws ServerExceptionInterface + * @throws TransportException + * @throws TransportExceptionInterface + */ + protected function batchList(OutputInterface $output, array $order, array $filter, array $select, int $elementsCount): array + { + $result = []; + + $output->writeln(['', '1. batch requests - ordered, count total elements...', '']); + $result['order_count'] = $this->getBatchWithCountQueryTime($output, $order, $filter, $select, $elementsCount); + + $output->writeln(['', '2. batch requests - ordered, without count total elements...', '']); + $result['order_without_count'] = $this->getBatchWithoutCountQueryTime($output, $order, $filter, $select, $elementsCount); + + $output->writeln(['', '3. batch requests - default order, count total elements...', '']); + $result['without_order_count'] = $this->getBatchWithCountQueryTime($output, [], $filter, $select, $elementsCount); + + $output->writeln(['', '4. batch requests - default order, without count total elements...', '']); + $result['without_order_without_count'] = $this->getBatchWithoutCountQueryTime($output, [], $filter, $select, $elementsCount);; + + return $result; + } + + /** + * @param OutputInterface $output + * @param array $order + * @param array $filter + * @param array $select + * @param int $elementsCount + * + * @return float + * @throws BaseException + * @throws ClientExceptionInterface + * @throws RedirectionExceptionInterface + * @throws ServerExceptionInterface + * @throws TransportException + * @throws TransportExceptionInterface + */ + protected function getBatchWithCountQueryTime( + OutputInterface $output, + array $order, + array $filter, + array $select, + int $elementsCount + ): float { + $timeStart = microtime(true); + $progressBar = new ProgressBar($output, $elementsCount); + $progressBar->setFormat("%current%/%max% [%bar%] %percent:3s%%\n %memory:6s% | %status%\n"); + $progressBar->setMessage('wait first batch query result...', 'status'); + $progressBar->start(); + + $elementsFromBatchCount = 0; + foreach ($this->batch->getTraversableListWithCount('crm.contact.list', $order, $filter, $select, $elementsCount) as $queryItem) { + $curTime = microtime(true); + $elementsFromBatchCount++; + $progressBar->advance(); + + $progressBar->setMessage( + sprintf( + ' %s sec |# %s | %s - %s ', + round($curTime - $timeStart, 2), + $elementsFromBatchCount, + $queryItem['ID'], + $queryItem['NAME'] + ), + 'status' + ); + } + $timeEnd = microtime(true); + $progressBar->finish(); + + return $timeEnd - $timeStart; + } + + /** + * @param OutputInterface $output + * @param array $order + * @param array $filter + * @param array $select + * @param int $elementsCount + * + * @return float + * @throws BaseException + * @throws ClientExceptionInterface + * @throws RedirectionExceptionInterface + * @throws ServerExceptionInterface + * @throws TransportException + * @throws TransportExceptionInterface + */ + protected function getBatchWithoutCountQueryTime( + OutputInterface $output, + array $order, + array $filter, + array $select, + int $elementsCount + ): float { + $timeStart = microtime(true); + $progressBar = new ProgressBar($output, $elementsCount); + $progressBar->setFormat("%current%/%max% [%bar%] %percent:3s%%\n %memory:6s% | %status%\n"); + $progressBar->setMessage('wait first batch query result...', 'status'); + $progressBar->start(); + + $elementsFromBatchCount = 0; + foreach ($this->batch->getTraversableList('crm.contact.list', $order, $filter, $select, $elementsCount) as $queryItem) { + $curTime = microtime(true); + $elementsFromBatchCount++; + $progressBar->advance(); + + $progressBar->setMessage( + sprintf( + ' %s sec |# %s | %s - %s ', + round($curTime - $timeStart, 2), + $elementsFromBatchCount, + $queryItem['ID'], + $queryItem['NAME'] + ), + 'status' + ); + } + $timeEnd = microtime(true); + $progressBar->finish(); + + return $timeEnd - $timeStart; + } + + /** + * @param array $order + * @param array $filter + * @param array $select + * + * @return array + * @throws BaseException + * @throws TransportException + * @throws ClientExceptionInterface + * @throws RedirectionExceptionInterface + * @throws ServerExceptionInterface + * @throws TransportExceptionInterface + */ + protected function simpleList(array $order, array $filter, array $select): array + { + $default = $this->core->call( + 'crm.contact.list', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => 1, + ] + ); + $orderAndNoCount = $this->core->call( + 'crm.contact.list', + [ + 'order' => $order, + 'filter' => $filter, + 'select' => $select, + 'start' => -1, + ] + ); + $noOrderAndCount = $this->core->call( + 'crm.contact.list', + [ + 'order' => [], + 'filter' => $filter, + 'select' => $select, + 'start' => 1, + ] + ); + $noOrderAndNoCount = $this->core->call( + 'crm.contact.list', + [ + 'order' => [], + 'filter' => $filter, + 'select' => $select, + 'start' => -1, + ] + ); + + return [ + 'order_count' => $default->getResponseData()->getTime()->duration, + 'order_without_count' => $orderAndNoCount->getResponseData()->getTime()->duration, + 'without_order_count' => $noOrderAndCount->getResponseData()->getTime()->duration, + 'without_order_without_count' => $noOrderAndNoCount->getResponseData()->getTime()->duration, + ]; + } +} \ No newline at end of file diff --git a/tools/Commands/ShowFieldsDescriptionCommand.php b/tools/Commands/ShowFieldsDescriptionCommand.php new file mode 100644 index 00000000..d13cee95 --- /dev/null +++ b/tools/Commands/ShowFieldsDescriptionCommand.php @@ -0,0 +1,270 @@ + + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Bitrix24\SDK\Tools\Commands; + +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; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Helper\Table; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Question\ChoiceQuestion; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\Console\Attribute\AsCommand; + + +#[AsCommand( + name: 'b24:util:show-fields-description', + description: 'show entity fields description with table or phpDoc output format', + hidden: false +)] +class ShowFieldsDescriptionCommand extends Command +{ + protected LoggerInterface $logger; + protected CoreInterface $core; + protected const WEBHOOK_URL = 'webhook'; + protected const OUTPUT_FORMAT = 'output-format'; + + /** + * ListCommand constructor. + * + * @param LoggerInterface $logger + */ + public function __construct(LoggerInterface $logger) + { + // best practices recommend to call the parent constructor first and + // then set your own properties. That wouldn't work in this case + // because configure() needs the properties set in this constructor + $this->logger = $logger; + parent::__construct(); + } + + protected function configure(): void + { + $this + ->setDescription('show entity fields description with table or phpDoc output format') + ->setHelp('get list of *.fields methods and show fields description for selected entity') + ->addOption( + self::WEBHOOK_URL, + null, + InputOption::VALUE_REQUIRED, + 'bitrix24 incoming webhook', + '' + ) + ->addOption( + self::OUTPUT_FORMAT, + null, + InputOption::VALUE_OPTIONAL, + 'show fields as «table» or «class» header or function «property» enum or «select» property', + 'table' + ); + } + + /** + * @param InputInterface $input + * @param OutputInterface $output + * + * @return int + */ + protected function execute(InputInterface $input, OutputInterface $output): int + { + $b24Webhook = (string)$input->getOption(self::WEBHOOK_URL); + $outputFormat = strtolower($input->getOption(self::OUTPUT_FORMAT)); + + $io = new SymfonyStyle($input, $output); + try { + $this->core = (new CoreBuilder()) + ->withLogger($this->logger) + ->withCredentials(Credentials::createFromWebhook(new WebhookUrl($b24Webhook))) + ->build(); + + $methods = $this->core->call('methods', ['full' => true])->getResponseData()->getResult(); + $fieldsMethods = []; + foreach ($methods as $method) { + if (strpos($method, 'fields') !== false) { + $fieldsMethods[] = $method; + } + } + + $helper = $this->getHelper('question'); + $itemQuestion = new ChoiceQuestion( + 'Please select item number to see fields', + $fieldsMethods, + null + ); + $itemQuestion->setErrorMessage('Item number %s is invalid.'); + $selectedEntity = $helper->ask($input, $output, $itemQuestion); + $output->writeln('You have just selected: ' . $selectedEntity); + + $outputQuestion = new ChoiceQuestion( + 'Please select item number to see fields', + [ + 'class properties header', + 'hashmap for function argument', + 'enum for function argument', + 'table', + ], + 'table' + ); + $outputQuestion->setErrorMessage('Item number %s is invalid.'); + $outputFormat = $helper->ask($input, $output, $outputQuestion); + $output->writeln('You have just selected: ' . $outputFormat); + + $fields = $this->core->call($selectedEntity); + switch ($outputFormat) { + case 'table': + $this->showFieldsAsTable($output, $fields); + break; + case 'class properties header': + $this->showFieldsAsPhpDocClassHeader($output, $fields); + break; + case 'hashmap for function argument': + $this->showFieldsAsPhpDocFunctionProperty($output, $fields); + break; + case 'enum for function argument': + $this->showFieldsAsPhpDocFunctionSelectSuggest($output, $fields); + break; + default: + throw new \InvalidArgumentException(sprintf('unknown output format %s', $outputFormat)); + } + } catch (BaseException $exception) { + $io->caution('Bitrix24 error'); + $io->text( + [ + sprintf('%s', $exception->getMessage()), + ] + ); + } catch (\Throwable $exception) { + $io->caution('fatal error'); + $io->text( + [ + $exception->getMessage(), + $exception->getTraceAsString(), + ] + ); + } + $this->logger->debug('ListCommand.start.finish'); + + return self::SUCCESS; + } + + /** + * @param OutputInterface $output + * @param Response $fields + * + * @throws BaseException + */ + private function showFieldsAsPhpDocFunctionSelectSuggest(OutputInterface $output, Response $fields): void + { + $fieldsList = []; + foreach ($fields->getResponseData()->getResult() as $fieldCode => $fieldDescription) { + $fieldsList[] = sprintf("'%s'", $fieldCode); + } + $output->writeln(' * @param array $select = [' . implode(',', $fieldsList) . ']'); + } + + /** + * @param OutputInterface $output + * @param Response $fields + * + * @throws BaseException + */ + private function showFieldsAsPhpDocFunctionProperty(OutputInterface $output, Response $fields): void + { + $fieldsList = ['*', '* @param array{']; + foreach ($fields->getResponseData()->getResult() as $fieldCode => $fieldDescription) { + if (is_array($fieldDescription)) { + $phpDocType = match (strtolower($fieldDescription['type'])) { + 'integer' => 'int', + default => 'string', + }; + } else { + $phpDocType = 'mixed'; + } + + $fieldsList[] = sprintf('* %s?: %s,', $fieldCode, $phpDocType); + } + $fieldsList[] = '* } $fields'; + $fieldsList[] = '*'; + $output->writeln($fieldsList); + } + + /** + * @param OutputInterface $output + * @param Response $fields + * + * @throws BaseException + */ + private function showFieldsAsPhpDocClassHeader(OutputInterface $output, Response $fields): void + { + $fieldsList = ['/**', '*']; + foreach ($fields->getResponseData()->getResult() as $fieldCode => $fieldDescription) { + + if (is_array($fieldDescription)) { + $phpDocType = match (strtolower($fieldDescription['type'])) { + 'integer' => 'int', + default => 'string', + }; + } else { + $phpDocType = 'mixed'; + } + $fieldsList[] = sprintf('* @property-read %s $%s', $phpDocType, $fieldCode); + } + $fieldsList[] = '*/'; + $output->writeln($fieldsList); + } + + /** + * @param OutputInterface $output + * @param Response $fields + * + * @throws BaseException + */ + private function showFieldsAsTable(OutputInterface $output, Response $fields): void + { + $fieldsTable = []; + // some methods return description in upper case + $fields = array_change_key_case($fields->getResponseData()->getResult(), CASE_LOWER); + + foreach ($fields as $fieldCode => $fieldDescription) { + $fieldDescription = array_change_key_case($fieldDescription, CASE_LOWER); + if (!array_key_exists('title', $fieldDescription)) { + $fieldDescription['title'] = $fieldCode; + } + + $fieldsTable[] = [ + $fieldCode, + $fieldDescription['title'], + $fieldDescription['type'], + $fieldDescription['isrequired'] ? 'Y' : '', + $fieldDescription['isreadonly'] ? 'Y' : '', + $fieldDescription['isimmutable'] ? 'Y' : '', + $fieldDescription['ismultiple'] ? 'Y' : '', + $fieldDescription['isdynamic'] ? 'Y' : '', + ]; + } + + $table = new Table($output); + $table + ->setHeaders(['Code', 'Title', 'Type', 'isRequired', 'isReadOnly', 'isImmutable', 'isMultiple', 'isDynamic']) + ->setRows($fieldsTable); + $table->render(); + } +} \ No newline at end of file