From 7acaf7a1dfee02f35342be01a63cebfed8aa35ed Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 1 Apr 2024 02:23:27 +0600 Subject: [PATCH 001/138] Add workflow services and update changelog This update adds new workflow services which provide support for working with workflow templates. Additionally, a necessary update in the changelog has been made to provide transparency to users about the added 'bizproc' services and new features in the workflow module. This step towards enriching Bitrix24 SDK with workflow enhancements could help in managing workflows better and provide users with more flexibility and control. Signed-off-by: mesilov --- CHANGELOG.md | 1 + src/Services/ServiceBuilder.php | 10 ++++ .../Common/WorkflowAutoExecutionType.php | 13 +++++ .../Result/WorkflowTemplateItemResult.php | 50 ++++++++++++++++++ .../Result/WorkflowTemplatesResult.php | 28 ++++++++++ .../Workflows/Template/Service/Batch.php | 22 ++++++++ .../Workflows/Template/Service/Template.php | 52 +++++++++++++++++++ .../Workflows/WorkflowsServiceBuilder.php | 24 +++++++++ 8 files changed, 200 insertions(+) create mode 100644 src/Services/Workflows/Common/WorkflowAutoExecutionType.php create mode 100644 src/Services/Workflows/Template/Result/WorkflowTemplateItemResult.php create mode 100644 src/Services/Workflows/Template/Result/WorkflowTemplatesResult.php create mode 100644 src/Services/Workflows/Template/Service/Batch.php create mode 100644 src/Services/Workflows/Template/Service/Template.php create mode 100644 src/Services/Workflows/WorkflowsServiceBuilder.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 20495c42..c28d9aba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 2.0-beta.2 — 1.04.2024 ### Added +* add `bizproc` [services](https://github.com/mesilov/bitrix24-php-sdk/issues/376) ### Changed * updated [dependencies versions](https://github.com/mesilov/bitrix24-php-sdk/issues/373): * require diff --git a/src/Services/ServiceBuilder.php b/src/Services/ServiceBuilder.php index 2f7b1ca3..ad7615ca 100644 --- a/src/Services/ServiceBuilder.php +++ b/src/Services/ServiceBuilder.php @@ -13,6 +13,7 @@ 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 { @@ -120,4 +121,13 @@ public function getTelephonyScope(): TelephonyServiceBuilder 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__]; + } } \ No newline at end of file diff --git a/src/Services/Workflows/Common/WorkflowAutoExecutionType.php b/src/Services/Workflows/Common/WorkflowAutoExecutionType.php new file mode 100644 index 00000000..d8684bce --- /dev/null +++ b/src/Services/Workflows/Common/WorkflowAutoExecutionType.php @@ -0,0 +1,13 @@ +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 DateTimeImmutable::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..062ad2d0 --- /dev/null +++ b/src/Services/Workflows/Template/Result/WorkflowTemplatesResult.php @@ -0,0 +1,28 @@ +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..8121e292 --- /dev/null +++ b/src/Services/Workflows/Template/Service/Batch.php @@ -0,0 +1,22 @@ +batch = $batch; + } + + /** + * The method bizproc.workflow.template.list returns list of workflow templates, specified for a site. This method requires administrator access permissions. + * @param array $select + * @param array $filter + * @return Workflows\Template\Result\WorkflowTemplatesResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/wirkflow_template/bizproc_workflow_template_list.php + */ + 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/WorkflowsServiceBuilder.php b/src/Services/Workflows/WorkflowsServiceBuilder.php new file mode 100644 index 00000000..0c4fdaed --- /dev/null +++ b/src/Services/Workflows/WorkflowsServiceBuilder.php @@ -0,0 +1,24 @@ +serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Workflows\Template\Service\Template( + new Template\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } +} \ No newline at end of file From bca364992493e4818a1e88e31c94a7e79a1b7715 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 1 Apr 2024 02:49:06 +0600 Subject: [PATCH 002/138] Add Workflow service and associated classes The update introduces a new Workflow service in the WorkflowsServiceBuilder, including supporting classes such as Batch and WorkflowInstanceItemResult. It also includes methods for workflow instances and their results. The additions provide functionality to list launched workflows and handle batch operations. Signed-off-by: mesilov --- .../Result/WorkflowInstanceItemResult.php | 46 +++++++++++++++ .../Result/WorkflowInstancesResult.php | 26 +++++++++ .../Workflows/Workflow/Service/Batch.php | 17 ++++++ .../Workflows/Workflow/Service/Workflow.php | 56 +++++++++++++++++++ .../Workflows/WorkflowsServiceBuilder.php | 15 ++++- 5 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 src/Services/Workflows/Workflow/Result/WorkflowInstanceItemResult.php create mode 100644 src/Services/Workflows/Workflow/Result/WorkflowInstancesResult.php create mode 100644 src/Services/Workflows/Workflow/Service/Batch.php create mode 100644 src/Services/Workflows/Workflow/Service/Workflow.php diff --git a/src/Services/Workflows/Workflow/Result/WorkflowInstanceItemResult.php b/src/Services/Workflows/Workflow/Result/WorkflowInstanceItemResult.php new file mode 100644 index 00000000..29375da0 --- /dev/null +++ b/src/Services/Workflows/Workflow/Result/WorkflowInstanceItemResult.php @@ -0,0 +1,46 @@ +data[$offset]; + case 'DOCUMENT_ID': + if ($this->data[$offset] !== '') { + // "DEAL_158310" + return (int)substr($this->data[$offset], strpos($this->data[$offset], '_')+1); + } + return null; + case 'MODIFIED': + case 'STARTED': + if ($this->data[$offset] !== '') { + return DateTimeImmutable::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/WorkflowInstancesResult.php b/src/Services/Workflows/Workflow/Result/WorkflowInstancesResult.php new file mode 100644 index 00000000..97be077c --- /dev/null +++ b/src/Services/Workflows/Workflow/Result/WorkflowInstancesResult.php @@ -0,0 +1,26 @@ +getCoreResponse()->getResponseData()->getResult() as $item) { + $res[] = new WorkflowInstanceItemResult($item); + } + + return $res; + } +} \ 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..653cd4f7 --- /dev/null +++ b/src/Services/Workflows/Workflow/Service/Batch.php @@ -0,0 +1,17 @@ +batch = $batch; + } + + /** + * returns list of launched workflows + * + * @param array $select + * @param array $order + * @param array $filter + * @return Workflows\Workflow\Result\WorkflowInstancesResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/workflow/bizproc_workflow_instances.php + */ + 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 index 0c4fdaed..670ab4af 100644 --- a/src/Services/Workflows/WorkflowsServiceBuilder.php +++ b/src/Services/Workflows/WorkflowsServiceBuilder.php @@ -13,7 +13,20 @@ public function template(): Workflows\Template\Service\Template { if (!isset($this->serviceCache[__METHOD__])) { $this->serviceCache[__METHOD__] = new Workflows\Template\Service\Template( - new Template\Service\Batch($this->batch, $this->log), + new Workflows\Template\Service\Batch($this->batch, $this->log), + $this->core, + $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 ); From b23306f38b4afd91899e915d033cfc61529e1e65 Mon Sep 17 00:00:00 2001 From: mesilov Date: Tue, 2 Apr 2024 03:03:06 +0600 Subject: [PATCH 003/138] Add workflow start methods and related classes Two new classes, WorkflowInstanceStartResult and WorkflowDocumentType, have been created. A start method has been introduced in the workflow service responsible for initiating a new workflow instance. It covers different types of document workflows, handles exceptions, and provides clear argument invalidation messages. Signed-off-by: mesilov --- .../Workflows/Common/WorkflowDocumentType.php | 26 ++++++++ .../Result/WorkflowInstanceStartResult.php | 15 +++++ .../Workflows/Workflow/Service/Workflow.php | 63 +++++++++++++++++++ 3 files changed, 104 insertions(+) create mode 100644 src/Services/Workflows/Common/WorkflowDocumentType.php create mode 100644 src/Services/Workflows/Workflow/Result/WorkflowInstanceStartResult.php diff --git a/src/Services/Workflows/Common/WorkflowDocumentType.php b/src/Services/Workflows/Common/WorkflowDocumentType.php new file mode 100644 index 00000000..1e9a4682 --- /dev/null +++ b/src/Services/Workflows/Common/WorkflowDocumentType.php @@ -0,0 +1,26 @@ +getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Workflow/Service/Workflow.php b/src/Services/Workflows/Workflow/Service/Workflow.php index 7c96b37d..cb9d00d5 100644 --- a/src/Services/Workflows/Workflow/Service/Workflow.php +++ b/src/Services/Workflows/Workflow/Service/Workflow.php @@ -6,6 +6,7 @@ use Bitrix24\SDK\Core\Contracts\CoreInterface; 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; @@ -26,6 +27,68 @@ public function __construct( $this->batch = $batch; } + /** + * 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 + * + */ + public function start( + Workflows\Common\WorkflowDocumentType $workflowDocumentType, + int $bizProcTemplateId, + int $entityId, + array $callParameters = [], + int $smartProcessId = null + ): Workflows\Workflow\Result\WorkflowInstanceStartResult + { + switch ($workflowDocumentType) { + case Workflows\Common\WorkflowDocumentType::crmLead: + $documentId = ['crm', $workflowDocumentType->value, sprintf('LEAD_%s', $entityId)]; + break; + case Workflows\Common\WorkflowDocumentType::crmCompany: + $documentId = ['crm', $workflowDocumentType->value, sprintf('COMPANY_%s', $entityId)]; + break; + case Workflows\Common\WorkflowDocumentType::crmContact: + $documentId = ['crm', $workflowDocumentType->value, sprintf('CONTACT_%s', $entityId)]; + break; + case Workflows\Common\WorkflowDocumentType::crmDeal: + $documentId = ['crm', $workflowDocumentType->value, sprintf('DEAL_%s', $entityId)]; + break; + case Workflows\Common\WorkflowDocumentType::discBizProcDocument: + $documentId = ['disk', $workflowDocumentType->value, $entityId]; + break; + case Workflows\Common\WorkflowDocumentType::listBizProcDocumentLists: + case Workflows\Common\WorkflowDocumentType::listBizProcDocument: + $documentId = ['lists', $workflowDocumentType->value, $entityId]; + break; + case Workflows\Common\WorkflowDocumentType::smartProcessDynamic: + if ($smartProcessId === null) { + throw new InvalidArgumentException('smartProcessId not set'); + } + $documentId = ['crm', $workflowDocumentType->value, sprintf('DYNAMIC_%s_%s', $smartProcessId, $entityId)]; + break; + case Workflows\Common\WorkflowDocumentType::task: + $documentId = ['tasks', $workflowDocumentType->value, $entityId]; + break; + case Workflows\Common\WorkflowDocumentType::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 * From 7cefd1141ee86f458968b277d726559246272506 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 4 Apr 2024 01:38:18 +0600 Subject: [PATCH 004/138] Add enum `DealSemanticStage` and update property types in `DealItemResult` This commit introduces the `DealSemanticStage` enum, furthering the options available for the `STAGE_SEMANTIC_ID` field of the `DealItemResult` class. This change provides more precise type information. Also, the types of several properties in the `DealItemResult` class are updated to nullable ones to better reflect possible data states. Signed-off-by: mesilov --- CHANGELOG.md | 33 ++++++--- .../CRM/Common/Result/AbstractCrmItem.php | 6 ++ .../CRM/Deal/Result/DealItemResult.php | 70 +++++++++---------- .../CRM/Deal/Result/DealSemanticStage.php | 13 ++++ 4 files changed, 76 insertions(+), 46 deletions(-) create mode 100644 src/Services/CRM/Deal/Result/DealSemanticStage.php diff --git a/CHANGELOG.md b/CHANGELOG.md index c28d9aba..019fa113 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,16 +3,22 @@ ## 2.0-beta.2 — 1.04.2024 ### Added + * add `bizproc` [services](https://github.com/mesilov/bitrix24-php-sdk/issues/376) + ### 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.*` + * 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` + ### Bugfix + ### etc ## 2.0-beta.1 — 18.02.2024 @@ -39,13 +45,13 @@ * 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 `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 +* add [Catalog](https://github.com/mesilov/bitrix24-php-sdk/issues/364) scope services support ### Changed @@ -60,7 +66,7 @@ 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`: +* ❗Changes in `Bitrix24\SDK\Application\Contracts\Bitrix24Account\Bitrix24AccountInterface`: * method `getContactPerson` renamed to `getContactPersonId` * added method `getApplicationVersion` * added method `updateApplicationVersion` @@ -70,7 +76,7 @@ * added method `markAsDeactivated` * added method `getBitrix24UserId` * removed method `markAccountAsDeleted` - * changed method `markAsActive` + * changed method `markAsActive` * ❗Changes in `Bitrix24\SDK\Application\Contracts\Bitrix24Account\Bitrix24AccountRepositoryInterface`: * method `saveAccount` renamed to `save` * method `deleteAccount` renamed to `delete` @@ -86,7 +92,8 @@ * 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 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 @@ -159,9 +166,13 @@ 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` diff --git a/src/Services/CRM/Common/Result/AbstractCrmItem.php b/src/Services/CRM/Common/Result/AbstractCrmItem.php index 84ffb151..dafb3540 100644 --- a/src/Services/CRM/Common/Result/AbstractCrmItem.php +++ b/src/Services/CRM/Common/Result/AbstractCrmItem.php @@ -10,6 +10,7 @@ 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 DateTimeImmutable; use Money\Currency; @@ -172,6 +173,11 @@ public function __get($offset) case 'currencyId': case 'accountCurrencyId': return new Currency($this->data[$offset]); + case 'STAGE_SEMANTIC_ID': + if ($this->data[$offset] !== null) { + return DealSemanticStage::from($this->data[$offset]); + } + return null; default: return $this->data[$offset] ?? null; } diff --git a/src/Services/CRM/Deal/Result/DealItemResult.php b/src/Services/CRM/Deal/Result/DealItemResult.php index a77faa40..601e527e 100644 --- a/src/Services/CRM/Deal/Result/DealItemResult.php +++ b/src/Services/CRM/Deal/Result/DealItemResult.php @@ -10,41 +10,41 @@ /** * Class DealItemResult * - * @property-read int $ID - * @property-read string $TITLE deal title - * @property-read string|null $TYPE_ID - * @property-read string|null $CATEGORY_ID - * @property-read string $STAGE_ID - * @property-read string $STAGE_SEMANTIC_ID - * @property-read bool $IS_NEW - * @property-read bool $IS_RECURRING - * @property-read string|null $PROBABILITY - * @property-read string $CURRENCY_ID - * @property-read string $OPPORTUNITY - * @property-read bool $IS_MANUAL_OPPORTUNITY - * @property-read string $TAX_VALUE - * @property-read int $LEAD_ID - * @property-read int $COMPANY_ID - * @property-read int $CONTACT_ID - * @property-read int $QUOTE_ID - * @property-read DateTimeInterface $BEGINDATE - * @property-read DateTimeInterface $CLOSEDATE - * @property-read bool $OPENED - * @property-read bool $CLOSED - * @property-read string|null $COMMENTS - * @property-read string|null $ADDITIONAL_INFO - * @property-read string|null $LOCATION_ID - * @property-read bool $IS_RETURN_CUSTOMER - * @property-read bool $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 + * @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 string|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 + * @property-read int|null $QUOTE_ID + * @property-read DateTimeInterface|null $BEGINDATE + * @property-read DateTimeInterface|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 { diff --git a/src/Services/CRM/Deal/Result/DealSemanticStage.php b/src/Services/CRM/Deal/Result/DealSemanticStage.php new file mode 100644 index 00000000..7fc7dde6 --- /dev/null +++ b/src/Services/CRM/Deal/Result/DealSemanticStage.php @@ -0,0 +1,13 @@ + Date: Sun, 21 Apr 2024 01:37:32 +0600 Subject: [PATCH 005/138] Add new specific workflow exceptions Two new specific exceptions have been added, 'ActivityOrRobotAlreadyInstalledException' and 'ActivityOrRobotValidationFailureException' in the workflow services. These exceptions are to be thrown in situations where an activity or robot is already installed or fails validation. This improves error handling by distinguishing specific scenarios during the API's error handling process. Signed-off-by: mesilov --- src/Core/ApiLevelErrorHandler.php | 10 ++++++---- src/Core/Core.php | 10 ++++++++++ .../ActivityOrRobotAlreadyInstalledException.php | 9 +++++++++ .../ActivityOrRobotValidationFailureException.php | 9 +++++++++ 4 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 src/Services/Workflows/Exceptions/ActivityOrRobotAlreadyInstalledException.php create mode 100644 src/Services/Workflows/Exceptions/ActivityOrRobotValidationFailureException.php diff --git a/src/Core/ApiLevelErrorHandler.php b/src/Core/ApiLevelErrorHandler.php index b25deaee..dd2232b4 100644 --- a/src/Core/ApiLevelErrorHandler.php +++ b/src/Core/ApiLevelErrorHandler.php @@ -8,14 +8,12 @@ use Bitrix24\SDK\Core\Exceptions\MethodNotFoundException; use Bitrix24\SDK\Core\Exceptions\OperationTimeLimitExceededException; use Bitrix24\SDK\Core\Exceptions\QueryLimitExceededException; +use Bitrix24\SDK\Services\Workflows\Exceptions\ActivityOrRobotAlreadyInstalledException; +use Bitrix24\SDK\Services\Workflows\Exceptions\ActivityOrRobotValidationFailureException; use Psr\Log\LoggerInterface; /** * Handle api-level errors and throw related exception - * - * Class ApiLevelErrorHandler - * - * @package Bitrix24\SDK\Core */ class ApiLevelErrorHandler { @@ -90,6 +88,10 @@ private function handleError(array $responseBody, ?string $batchCommandId = null 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)); default: throw new BaseException(sprintf('%s - %s %s', $errorCode, $errorDescription, $batchErrorPrefix)); } diff --git a/src/Core/Core.php b/src/Core/Core.php index 73511395..979aa78a 100644 --- a/src/Core/Core.php +++ b/src/Core/Core.php @@ -108,6 +108,16 @@ public function call(string $apiMethod, array $parameters = []): Response // 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', + [ + 'body' => $body, + ] + ); + $this->apiLevelErrorHandler->handle($body); + break; case StatusCodeInterface::STATUS_UNAUTHORIZED: $body = $apiCallResponse->toArray(false); $this->logger->debug( diff --git a/src/Services/Workflows/Exceptions/ActivityOrRobotAlreadyInstalledException.php b/src/Services/Workflows/Exceptions/ActivityOrRobotAlreadyInstalledException.php new file mode 100644 index 00000000..bb3ee0e6 --- /dev/null +++ b/src/Services/Workflows/Exceptions/ActivityOrRobotAlreadyInstalledException.php @@ -0,0 +1,9 @@ + Date: Sun, 21 Apr 2024 01:46:06 +0600 Subject: [PATCH 006/138] Add automation rule support for workflows This update introduces a new Robot service to the Workflows, which adds support for automation rules in the application. It includes functionalities for registration, deletion and updating of these rules, along with related result reporting features and work property enumeration. Signed-off-by: mesilov --- .../Workflows/Common/WorkflowPropertyType.php | 18 ++ .../Robot/Result/AddedRobotResult.php | 15 ++ .../Robot/Result/UpdateRobotResult.php | 15 ++ .../Robot/Result/WorkflowRobotsResult.php | 19 +++ .../Workflows/Robot/Service/Robot.php | 159 ++++++++++++++++++ .../Workflows/WorkflowsServiceBuilder.php | 13 ++ 6 files changed, 239 insertions(+) create mode 100644 src/Services/Workflows/Common/WorkflowPropertyType.php create mode 100644 src/Services/Workflows/Robot/Result/AddedRobotResult.php create mode 100644 src/Services/Workflows/Robot/Result/UpdateRobotResult.php create mode 100644 src/Services/Workflows/Robot/Result/WorkflowRobotsResult.php create mode 100644 src/Services/Workflows/Robot/Service/Robot.php diff --git a/src/Services/Workflows/Common/WorkflowPropertyType.php b/src/Services/Workflows/Common/WorkflowPropertyType.php new file mode 100644 index 00000000..4ff90cf9 --- /dev/null +++ b/src/Services/Workflows/Common/WorkflowPropertyType.php @@ -0,0 +1,18 @@ +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..fe2d2c3b --- /dev/null +++ b/src/Services/Workflows/Robot/Result/UpdateRobotResult.php @@ -0,0 +1,15 @@ +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..95f2523a --- /dev/null +++ b/src/Services/Workflows/Robot/Result/WorkflowRobotsResult.php @@ -0,0 +1,19 @@ +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..5188d03b --- /dev/null +++ b/src/Services/Workflows/Robot/Service/Robot.php @@ -0,0 +1,159 @@ +batch = $batch; + } + + /** + * Registers new automation rule. + * + * @param string $code + * @param string $handlerUrl + * @param int $b24AuthUserId + * @param array $localizedRobotName + * @param bool $isUseSubscription + * @param array $properties + * @param bool $isUsePlacement + * @param array $returnProperties + * + * @return AddedRobotResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/app_automation_rules/bizproc_robot_add.php + */ + 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 + */ + 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. + * + * @param string $robotCode + * @return DeletedItemResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/app_automation_rules/bizproc_robot_delete.php + */ + public function delete(string $robotCode): DeletedItemResult + { + return new DeletedItemResult( + $this->core->call('bizproc.robot.delete', [ + 'CODE' => $robotCode + ])); + } + + /** + * updates fields of automation rules + * + * @param string $code + * @param string|null $handlerUrl + * @param int|null $b24AuthUserId + * @param array|null $localizedRobotName + * @param bool $isUseSubscription + * @param array|null $properties + * @param bool $isUsePlacement + * @param array|null $returnProperties + * @return UpdateRobotResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/app_automation_rules/bizproc_robot_update.php + */ + 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; + } + + 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/WorkflowsServiceBuilder.php b/src/Services/Workflows/WorkflowsServiceBuilder.php index 670ab4af..6a86b4c9 100644 --- a/src/Services/Workflows/WorkflowsServiceBuilder.php +++ b/src/Services/Workflows/WorkflowsServiceBuilder.php @@ -9,6 +9,19 @@ class WorkflowsServiceBuilder extends AbstractServiceBuilder { + 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 template(): Workflows\Template\Service\Template { if (!isset($this->serviceCache[__METHOD__])) { From be9013cad39f50eb9238eb09ce672f7ae56ae8e8 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 21 Apr 2024 19:59:01 +0600 Subject: [PATCH 007/138] Add functionality to handle Workflow Events New classes have been added to handle Workflow Events, which support the initialization of the Event Service, handling Robot Requests, and sending events with return values. Modifications have also been done on the AccessToken and WorkflowsServiceBuilder classes to support this new feature. Signed-off-by: mesilov --- src/Core/Credentials/AccessToken.php | 11 +++- .../Event/Result/EventSendResult.php | 15 +++++ .../Workflows/Event/Service/Batch.php | 17 ++++++ .../Workflows/Event/Service/Event.php | 55 +++++++++++++++++++ .../Workflows/WorkflowsServiceBuilder.php | 13 +++++ 5 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 src/Services/Workflows/Event/Result/EventSendResult.php create mode 100644 src/Services/Workflows/Event/Service/Batch.php create mode 100644 src/Services/Workflows/Event/Service/Event.php diff --git a/src/Core/Credentials/AccessToken.php b/src/Core/Credentials/AccessToken.php index 8cefe7d4..338974bf 100644 --- a/src/Core/Credentials/AccessToken.php +++ b/src/Core/Credentials/AccessToken.php @@ -6,6 +6,7 @@ use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation; /** * Class AccessToken @@ -78,10 +79,16 @@ public static function initFromArray(array $request): self ); } + public static function initFromRobotRequest(Request $request): self + { + $requestFields = $request->request->all(); + return self::initFromArray($requestFields['auth']); + } + /** - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws InvalidArgumentException */ - public static function initFromPlacementRequest(Request $request): self + public static function initFromPlacementRequest(HttpFoundation\Request $request): self { $requestFields = $request->request->all(); if (!array_key_exists('AUTH_ID', $requestFields)) { diff --git a/src/Services/Workflows/Event/Result/EventSendResult.php b/src/Services/Workflows/Event/Result/EventSendResult.php new file mode 100644 index 00000000..c5acfee5 --- /dev/null +++ b/src/Services/Workflows/Event/Result/EventSendResult.php @@ -0,0 +1,15 @@ +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..feaba616 --- /dev/null +++ b/src/Services/Workflows/Event/Service/Batch.php @@ -0,0 +1,17 @@ +batch = $batch; + } + + /** + * returns output parameters to an activity. Parameters are specified in the activity description. + * + * @param string $eventToken + * @param array $returnValues + * @param string|null $logMessage + * + * @return Workflows\Event\Result\EventSendResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/workflows_events/bizproc_event_send.php + */ + 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/WorkflowsServiceBuilder.php b/src/Services/Workflows/WorkflowsServiceBuilder.php index 6a86b4c9..0ea134c7 100644 --- a/src/Services/Workflows/WorkflowsServiceBuilder.php +++ b/src/Services/Workflows/WorkflowsServiceBuilder.php @@ -9,6 +9,19 @@ 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__])) { From 35d07bf229d1e28311b3cae27f01b2f64e3ab5bc Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 21 Apr 2024 20:27:28 +0600 Subject: [PATCH 008/138] Update CHANGELOG.md for 2.0-beta.3 release This commit updates the CHANGELOG.md to reflect the changes going into the 2.0-beta.3 release of the bitrix24-php-sdk. This includes the addition of the 'bizproc' scope and related services for working with workflows, as well as a new method for initializing from a robot request. Signed-off-by: mesilov --- CHANGELOG.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 019fa113..bf9ee21d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,17 @@ # bitrix24-php-sdk change log -## 2.0-beta.2 — 1.04.2024 +## 2.0-beta.3 — 1.05.2024 ### Added +* add scope `bizproc` and [services](https://github.com/mesilov/bitrix24-php-sdk/issues/376) for work with workflows: + * `Workflow` + * `Template` + * `Robot` + * `Event` +* add method `Bitrix24\SDK\Core\Credentials\AccessToken::initFromRobotRequest` +* -* add `bizproc` [services](https://github.com/mesilov/bitrix24-php-sdk/issues/376) +## 2.0-beta.2 — 1.04.2024 ### Changed @@ -17,10 +24,6 @@ * `phpunit/phpunit` `10.5.*` → `11.0.*` * added enum `DealSemanticStage` for deal field `STAGE_SEMANTIC_ID` -### Bugfix - -### etc - ## 2.0-beta.1 — 18.02.2024 ### Added From 0be7858de3d66d8ed13d42cbd020653750cc49a9 Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 1 May 2024 22:07:39 +0600 Subject: [PATCH 009/138] Added new workflows and activities service functionalities This commit introduces new functionalities for workflows and activities services. It includes adding methods to enable recording data in the workflow log, retrieval of installed activities, option to update activity fields, add and delete activities. Also, added necessary result classes and updated the access token method name. Signed-off-by: mesilov --- CHANGELOG.md | 3 +- src/Core/Credentials/AccessToken.php | 2 +- .../Activity/Result/AddedActivityResult.php | 15 ++ .../Result/AddedMessageToLogResult.php | 15 ++ .../Activity/Result/UpdateActivityResult.php | 15 ++ .../Result/WorkflowActivitiesResult.php | 19 ++ .../Workflows/Activity/Service/Activity.php | 200 ++++++++++++++++++ .../Workflows/Activity/Service/Batch.php | 22 ++ .../Common/WorkflowActivityDocumentType.php | 41 ++++ .../Workflows/Workflow/Service/Workflow.php | 1 + .../Workflows/WorkflowsServiceBuilder.php | 13 ++ 11 files changed, 344 insertions(+), 2 deletions(-) create mode 100644 src/Services/Workflows/Activity/Result/AddedActivityResult.php create mode 100644 src/Services/Workflows/Activity/Result/AddedMessageToLogResult.php create mode 100644 src/Services/Workflows/Activity/Result/UpdateActivityResult.php create mode 100644 src/Services/Workflows/Activity/Result/WorkflowActivitiesResult.php create mode 100644 src/Services/Workflows/Activity/Service/Activity.php create mode 100644 src/Services/Workflows/Activity/Service/Batch.php create mode 100644 src/Services/Workflows/Common/WorkflowActivityDocumentType.php diff --git a/CHANGELOG.md b/CHANGELOG.md index bf9ee21d..41a74226 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,8 @@ * `Template` * `Robot` * `Event` -* add method `Bitrix24\SDK\Core\Credentials\AccessToken::initFromRobotRequest` +* add `WorkflowActivityDocumentType` +* add method `Bitrix24\SDK\Core\Credentials\AccessToken::initFromWorkflowRequest` * ## 2.0-beta.2 — 1.04.2024 diff --git a/src/Core/Credentials/AccessToken.php b/src/Core/Credentials/AccessToken.php index 338974bf..7ecf5bfb 100644 --- a/src/Core/Credentials/AccessToken.php +++ b/src/Core/Credentials/AccessToken.php @@ -79,7 +79,7 @@ public static function initFromArray(array $request): self ); } - public static function initFromRobotRequest(Request $request): self + public static function initFromWorkflowRequest(Request $request): self { $requestFields = $request->request->all(); return self::initFromArray($requestFields['auth']); diff --git a/src/Services/Workflows/Activity/Result/AddedActivityResult.php b/src/Services/Workflows/Activity/Result/AddedActivityResult.php new file mode 100644 index 00000000..676c1217 --- /dev/null +++ b/src/Services/Workflows/Activity/Result/AddedActivityResult.php @@ -0,0 +1,15 @@ +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..ca90c650 --- /dev/null +++ b/src/Services/Workflows/Activity/Result/AddedMessageToLogResult.php @@ -0,0 +1,15 @@ +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..99926003 --- /dev/null +++ b/src/Services/Workflows/Activity/Result/UpdateActivityResult.php @@ -0,0 +1,15 @@ +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..1b140482 --- /dev/null +++ b/src/Services/Workflows/Activity/Result/WorkflowActivitiesResult.php @@ -0,0 +1,19 @@ +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..43533818 --- /dev/null +++ b/src/Services/Workflows/Activity/Service/Activity.php @@ -0,0 +1,200 @@ +batch = $batch; + } + + /** + * This method records data in the workflow log. + * @param string $eventToken + * @param string $message + * @return Workflows\Activity\Result\AddedMessageToLogResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/app_activities/bizproc_activity_list.php + */ + 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 + */ + 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 WorkflowActivityDocumentType $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 + */ + public function add( + string $code, + string $handlerUrl, + int $b24AuthUserId, + array $localizedName, + array $localizedDescription, + bool $isUseSubscription, + array $properties, + bool $isUsePlacement, + array $returnProperties, + Workflows\Common\WorkflowActivityDocumentType $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. + * + * @param string $activityCode + * @return DeletedItemResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/app_activities/bizproc_activity_delete.php + */ + 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 WorkflowActivityDocumentType|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 + */ + public function update( + string $code, + ?string $handlerUrl, + ?int $b24AuthUserId, + ?array $localizedName, + ?array $localizedDescription, + ?bool $isUseSubscription, + ?array $properties, + ?bool $isUsePlacement, + ?array $returnProperties, + ?Workflows\Common\WorkflowActivityDocumentType $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; + } + 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..07d3fdb7 --- /dev/null +++ b/src/Services/Workflows/Activity/Service/Batch.php @@ -0,0 +1,22 @@ +moduleId, $this->entityId, $this->targetDocumentType]; + } + + 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/Workflow/Service/Workflow.php b/src/Services/Workflows/Workflow/Service/Workflow.php index cb9d00d5..848cd852 100644 --- a/src/Services/Workflows/Workflow/Service/Workflow.php +++ b/src/Services/Workflows/Workflow/Service/Workflow.php @@ -44,6 +44,7 @@ public function start( int $smartProcessId = null ): Workflows\Workflow\Result\WorkflowInstanceStartResult { + $documentId = null; switch ($workflowDocumentType) { case Workflows\Common\WorkflowDocumentType::crmLead: $documentId = ['crm', $workflowDocumentType->value, sprintf('LEAD_%s', $entityId)]; diff --git a/src/Services/Workflows/WorkflowsServiceBuilder.php b/src/Services/Workflows/WorkflowsServiceBuilder.php index 0ea134c7..3489d168 100644 --- a/src/Services/Workflows/WorkflowsServiceBuilder.php +++ b/src/Services/Workflows/WorkflowsServiceBuilder.php @@ -35,6 +35,19 @@ public function robot(): Workflows\Robot\Service\Robot 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 template(): Workflows\Template\Service\Template { if (!isset($this->serviceCache[__METHOD__])) { From 67f0abe575505e3f88504166dc4b554a5dc2117d Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 2 May 2024 02:30:24 +0600 Subject: [PATCH 010/138] Update dependencies and enhance workflows in CHANGELOG This commit updates the versions of the 'symfony/console' and 'symfony/dotenv' dependencies in the 'composer.json' file. Additionally, the CHANGELOG has been updated, expanding the description of workflow services and their features. Signed-off-by: mesilov --- CHANGELOG.md | 33 ++++++++++++++++++++++++++------- composer.json | 4 ++-- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41a74226..cc8946c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,15 +3,32 @@ ## 2.0-beta.3 — 1.05.2024 ### Added + * add scope `bizproc` and [services](https://github.com/mesilov/bitrix24-php-sdk/issues/376) for work with workflows: - * `Workflow` - * `Template` - * `Robot` - * `Event` -* add `WorkflowActivityDocumentType` + * `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` — 🛠️ WIP + * `Template` — 🛠️ WIP + * `Tasks` — 🛠️ WIP + * add `WorkflowActivityDocumentType` * add method `Bitrix24\SDK\Core\Credentials\AccessToken::initFromWorkflowRequest` -* - +* add dependencies + * require + * `symfony/console` version `^6 || ^7` + * `symfony/dotenv` version `^6 || ^7` + ## 2.0-beta.2 — 1.04.2024 ### Changed @@ -97,7 +114,9 @@ * 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 diff --git a/composer.json b/composer.json index 4d19c130..90d39553 100644 --- a/composer.json +++ b/composer.json @@ -30,6 +30,8 @@ "ramsey/uuid": "^3 ||^4", "moneyphp/money": "^3 || ^4", "symfony/http-client": "^6 || ^7", + "symfony/console": "^6 || ^7", + "symfony/dotenv": "^6 || ^7", "symfony/http-client-contracts": "^2 || ^3", "symfony/http-foundation": "^6 || ^7", "symfony/event-dispatcher": "^6 || ^7", @@ -39,8 +41,6 @@ "monolog/monolog": "3.5.*", "phpstan/phpstan": "1.10.*", "phpunit/phpunit": "11.0.*", - "symfony/console": "7.0.*", - "symfony/dotenv": "7.0.*", "symfony/debug-bundle": "7.0.*", "symfony/stopwatch": "7.0.*", "roave/security-advisories": "dev-master", From c90817a6362da396642f1ec47610b57168082b21 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 2 May 2024 02:31:01 +0600 Subject: [PATCH 011/138] Add workflow termination feature Implemented the ability to stop an active workflow in the Workflow service, returning the result in a new WorkflowTerminationResult class. Also updated the WorkflowActivityDocumentType class to replace targetDocumentType with targetDocumentId. Signed-off-by: mesilov --- .../Common/WorkflowActivityDocumentType.php | 4 ++-- .../Result/WorkflowTerminationResult.php | 15 +++++++++++++++ .../Workflows/Workflow/Service/Workflow.php | 16 ++++++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 src/Services/Workflows/Workflow/Result/WorkflowTerminationResult.php diff --git a/src/Services/Workflows/Common/WorkflowActivityDocumentType.php b/src/Services/Workflows/Common/WorkflowActivityDocumentType.php index 338c8f49..0348b664 100644 --- a/src/Services/Workflows/Common/WorkflowActivityDocumentType.php +++ b/src/Services/Workflows/Common/WorkflowActivityDocumentType.php @@ -9,14 +9,14 @@ public function __construct( public string $moduleId, public string $entityId, - public string $targetDocumentType, + public string $targetDocumentId, ) { } public function toArray(): array { - return [$this->moduleId, $this->entityId, $this->targetDocumentType]; + return [$this->moduleId, $this->entityId, $this->targetDocumentId]; } public static function buildForLead(): self diff --git a/src/Services/Workflows/Workflow/Result/WorkflowTerminationResult.php b/src/Services/Workflows/Workflow/Result/WorkflowTerminationResult.php new file mode 100644 index 00000000..a9ad8f88 --- /dev/null +++ b/src/Services/Workflows/Workflow/Result/WorkflowTerminationResult.php @@ -0,0 +1,15 @@ +getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Workflow/Service/Workflow.php b/src/Services/Workflows/Workflow/Service/Workflow.php index 848cd852..7a2abe12 100644 --- a/src/Services/Workflows/Workflow/Service/Workflow.php +++ b/src/Services/Workflows/Workflow/Service/Workflow.php @@ -27,6 +27,22 @@ public function __construct( $this->batch = $batch; } + /** + * Stops an active workflow. + * + * @param string $workflowId + * @param string $message + * @return Workflows\Workflow\Result\WorkflowTerminationResult + * @see https://training.bitrix24.com/rest_help/workflows/workflow/bizproc_workflow_terminate.php + */ + public function terminate(string $workflowId, string $message) + { + return new Workflows\Workflow\Result\WorkflowTerminationResult($this->core->call('bizproc.workflow.terminate', [ + 'ID' => $workflowId, + 'STATUE' => $message + ])); + } + /** * bizproc.workflow.start launches a worfklow * From 7a18a3ff18b69cb49e942de09d3ea7a56ceac386 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 4 May 2024 01:07:45 +0600 Subject: [PATCH 012/138] Add handling for 'access_denied' case in ErrorHandler Added case for 'access_denied' error status in the ApiLevelErrorHandler. Also replaced 'body' with 'rawResponse' in logging actions for more clarity. The Core.php file now throws the 'AuthForbiddenException' to the ErrorHandler to handle, leading to better error management. Signed-off-by: mesilov --- src/Core/ApiLevelErrorHandler.php | 3 +++ src/Core/Core.php | 13 ++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/Core/ApiLevelErrorHandler.php b/src/Core/ApiLevelErrorHandler.php index dd2232b4..c71a414e 100644 --- a/src/Core/ApiLevelErrorHandler.php +++ b/src/Core/ApiLevelErrorHandler.php @@ -4,6 +4,7 @@ namespace Bitrix24\SDK\Core; +use Bitrix24\SDK\Core\Exceptions\AuthForbiddenException; use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Exceptions\MethodNotFoundException; use Bitrix24\SDK\Core\Exceptions\OperationTimeLimitExceededException; @@ -82,6 +83,8 @@ private function handleError(array $responseBody, ?string $batchCommandId = null } switch ($errorCode) { + case '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': diff --git a/src/Core/Core.php b/src/Core/Core.php index 979aa78a..1966c773 100644 --- a/src/Core/Core.php +++ b/src/Core/Core.php @@ -113,7 +113,7 @@ public function call(string $apiMethod, array $parameters = []): Response $this->logger->notice( 'bad request', [ - 'body' => $body, + 'rawResponse' => $body, ] ); $this->apiLevelErrorHandler->handle($body); @@ -123,7 +123,7 @@ public function call(string $apiMethod, array $parameters = []): Response $this->logger->debug( 'UNAUTHORIZED request', [ - 'body' => $body, + 'rawResponse' => $body, ] ); @@ -158,20 +158,23 @@ public function call(string $apiMethod, array $parameters = []): Response } 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, ] ); - throw new AuthForbiddenException(sprintf('authorisation forbidden for portal %s ', $this->apiClient->getCredentials()->getDomainUrl())); + $this->apiLevelErrorHandler->handle($body); + break; case StatusCodeInterface::STATUS_SERVICE_UNAVAILABLE: $body = $apiCallResponse->toArray(false); $this->logger->notice( 'bitrix24 portal unavailable', [ - 'body' => $body, + 'rawResponse' => $body, ] ); $this->apiLevelErrorHandler->handle($body); @@ -182,7 +185,7 @@ public function call(string $apiMethod, array $parameters = []): Response 'unhandled server status', [ 'httpStatus' => $apiCallResponse->getStatusCode(), - 'body' => $body, + 'rawResponse' => $body, ] ); $this->apiLevelErrorHandler->handle($body); From 1f71b1afea6b68f85976b3c59e82d37af8d34294 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 4 May 2024 01:08:30 +0600 Subject: [PATCH 013/138] Removed the integration.yml workflow The integration.yml GitHub workflow has been eliminated, as seen in the deletion of related codes and configurations. The workflow was responsible for running integration tests in different PHP versions and operating systems. Signed-off-by: mesilov --- .github/workflows/integration.yml | 60 ------------------------------- 1 file changed, 60 deletions(-) delete mode 100644 .github/workflows/integration.yml diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml deleted file mode 100644 index 2a6b4634..00000000 --- a/.github/workflows/integration.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: "Integration tests" - -on: - push: - branches: - - dev - pull_request: - -env: - COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist" - BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK: ${{ secrets.BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK }} - -jobs: - tests: - name: "Integration 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 }}" - ini-values: variables_order=EGPCS - env: - BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK: ${{ secrets.BITRIX24_PHP_SDK_PLAYGROUND_WEBHOOK }} - - - 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 From 3ff8abf2ad803aefbe80846d5fbd529bd927a298 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 4 May 2024 02:08:28 +0600 Subject: [PATCH 014/138] Refactor Workflows services and add new features Updated the structure of Workflows services and incorporated new functionalities. This includes the ability to delete and launch workflows, and stop active ones. Additionally, implemented workflow templates add and delete features. Introduced Base64 encoding within the file system and now handle file not found exception. Signed-off-by: mesilov --- CHANGELOG.md | 18 ++++-- composer.json | 2 + src/Core/ApiLevelErrorHandler.php | 5 ++ src/Core/Exceptions/FileNotFoundException.php | 9 +++ .../Filesystem/Base64Encoder.php | 41 ++++++++++++++ .../Workflows/Activity/Service/Activity.php | 50 ++++++++--------- .../Workflows/Common/DocumentType.php | 26 +++++++++ .../Common/WorkflowActivityDocumentType.php | 41 -------------- .../Workflows/Common/WorkflowDocumentType.php | 51 +++++++++++------ .../Workflows/Template/Service/Template.php | 55 +++++++++++++++++++ .../Workflow/Result/WorkflowKillResult.php | 15 +++++ .../Workflows/Workflow/Service/Workflow.php | 49 +++++++++++------ .../Workflows/WorkflowsServiceBuilder.php | 7 +++ 13 files changed, 263 insertions(+), 106 deletions(-) create mode 100644 src/Core/Exceptions/FileNotFoundException.php create mode 100644 src/Infrastructure/Filesystem/Base64Encoder.php create mode 100644 src/Services/Workflows/Common/DocumentType.php delete mode 100644 src/Services/Workflows/Common/WorkflowActivityDocumentType.php create mode 100644 src/Services/Workflows/Workflow/Result/WorkflowKillResult.php diff --git a/CHANGELOG.md b/CHANGELOG.md index cc8946c6..9f483087 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,16 +19,24 @@ * `Event` – service for work with return parameters¨ * `send` – Returns the output parameters to the activity * `Providers` — deprecated methods, not implemented - * `Workflow` — 🛠️ WIP + * `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` — 🛠️ WIP * `Tasks` — 🛠️ WIP * add `WorkflowActivityDocumentType` * add method `Bitrix24\SDK\Core\Credentials\AccessToken::initFromWorkflowRequest` * add dependencies - * require - * `symfony/console` version `^6 || ^7` - * `symfony/dotenv` version `^6 || ^7` - + * require + * `symfony/console` version `^6 || ^7` + * `symfony/dotenv` version `^6 || ^7` + * `symfony/filesystem` version `^6 || ^7`, + * `symfony/mime` version `^6 || ^7`, +* add `\Bitrix24\SDK\Infrastructure\Filesystem\Base64Encoder` for work with base64 encoding +* add `\Bitrix24\SDK\Core\Exceptions\FileNotFoundException` if file not found + ## 2.0-beta.2 — 1.04.2024 ### Changed diff --git a/composer.json b/composer.json index 90d39553..8c93e362 100644 --- a/composer.json +++ b/composer.json @@ -32,6 +32,8 @@ "symfony/http-client": "^6 || ^7", "symfony/console": "^6 || ^7", "symfony/dotenv": "^6 || ^7", + "symfony/filesystem": "^6 || ^7", + "symfony/mime": "^6 || ^7", "symfony/http-client-contracts": "^2 || ^3", "symfony/http-foundation": "^6 || ^7", "symfony/event-dispatcher": "^6 || ^7", diff --git a/src/Core/ApiLevelErrorHandler.php b/src/Core/ApiLevelErrorHandler.php index c71a414e..4df6b664 100644 --- a/src/Core/ApiLevelErrorHandler.php +++ b/src/Core/ApiLevelErrorHandler.php @@ -81,9 +81,14 @@ private function handleError(array $responseBody, ?string $batchCommandId = null if ($batchCommandId !== null) { $batchErrorPrefix = sprintf(' batch command id: %s', $batchCommandId); } + // fix error code responses + if ($errorCode === '' && strtolower($errorDescription) === strtolower('You can delete ONLY templates created by current application')) { + $errorCode = 'bizproc_workflow_template_access_denied'; + } switch ($errorCode) { 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)); diff --git a/src/Core/Exceptions/FileNotFoundException.php b/src/Core/Exceptions/FileNotFoundException.php new file mode 100644 index 00000000..315dd5a6 --- /dev/null +++ b/src/Core/Exceptions/FileNotFoundException.php @@ -0,0 +1,9 @@ +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/Services/Workflows/Activity/Service/Activity.php b/src/Services/Workflows/Activity/Service/Activity.php index 43533818..5e1a63b9 100644 --- a/src/Services/Workflows/Activity/Service/Activity.php +++ b/src/Services/Workflows/Activity/Service/Activity.php @@ -12,7 +12,7 @@ use Bitrix24\SDK\Services\Workflows; use Bitrix24\SDK\Services\Workflows\Activity\Result\AddedActivityResult; use Bitrix24\SDK\Services\Workflows\Activity\Result\UpdateActivityResult; -use Bitrix24\SDK\Services\Workflows\Common\WorkflowActivityDocumentType; +use Bitrix24\SDK\Services\Workflows\Common\WorkflowDocumentType; use Psr\Log\LoggerInterface; class Activity extends AbstractService @@ -70,7 +70,7 @@ public function list(): Workflows\Activity\Result\WorkflowActivitiesResult * @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 WorkflowActivityDocumentType $documentType Tip of document, which will determine type of data for parameters. + * @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 @@ -79,17 +79,17 @@ public function list(): Workflows\Activity\Result\WorkflowActivitiesResult * @see https://training.bitrix24.com/rest_help/workflows/app_activities/bizproc_activity_add.php */ public function add( - string $code, - string $handlerUrl, - int $b24AuthUserId, - array $localizedName, - array $localizedDescription, - bool $isUseSubscription, - array $properties, - bool $isUsePlacement, - array $returnProperties, - Workflows\Common\WorkflowActivityDocumentType $documentType, - array $limitationFilter, + 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', [ @@ -137,7 +137,7 @@ function delete(string $activityCode): DeletedItemResult * @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 WorkflowActivityDocumentType|null $documentType Tip of document, which will determine type of data for parameters. + * @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 @@ -146,17 +146,17 @@ function delete(string $activityCode): DeletedItemResult * @see https://training.bitrix24.com/rest_help/workflows/app_activities/bizproc_activity_update.php */ public function update( - string $code, - ?string $handlerUrl, - ?int $b24AuthUserId, - ?array $localizedName, - ?array $localizedDescription, - ?bool $isUseSubscription, - ?array $properties, - ?bool $isUsePlacement, - ?array $returnProperties, - ?Workflows\Common\WorkflowActivityDocumentType $documentType, - ?array $limitationFilter, + 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 = []; diff --git a/src/Services/Workflows/Common/DocumentType.php b/src/Services/Workflows/Common/DocumentType.php new file mode 100644 index 00000000..cffde998 --- /dev/null +++ b/src/Services/Workflows/Common/DocumentType.php @@ -0,0 +1,26 @@ +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/WorkflowDocumentType.php b/src/Services/Workflows/Common/WorkflowDocumentType.php index 1e9a4682..0d8aa25c 100644 --- a/src/Services/Workflows/Common/WorkflowDocumentType.php +++ b/src/Services/Workflows/Common/WorkflowDocumentType.php @@ -4,23 +4,38 @@ namespace Bitrix24\SDK\Services\Workflows\Common; -enum WorkflowDocumentType: string +readonly class WorkflowDocumentType { - // 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'; + public function __construct( + public string $moduleId, + public string $entityId, + public string $targetDocumentId, + ) + { + } + + 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/Template/Service/Template.php b/src/Services/Workflows/Template/Service/Template.php index 2e9c85a8..fe8af1e8 100644 --- a/src/Services/Workflows/Template/Service/Template.php +++ b/src/Services/Workflows/Template/Service/Template.php @@ -7,6 +7,9 @@ use Bitrix24\SDK\Core\Contracts\CoreInterface; 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\Infrastructure\Filesystem\Base64Encoder; use Bitrix24\SDK\Services\AbstractService; use Bitrix24\SDK\Services\Workflows; use Psr\Log\LoggerInterface; @@ -15,15 +18,67 @@ class Template extends AbstractService { public Batch $batch; + private Base64Encoder $base64Encoder; public function __construct( Batch $batch, CoreInterface $core, + Base64Encoder $base64Encoder, LoggerInterface $log ) { parent::__construct($core, $log); $this->batch = $batch; + $this->base64Encoder = $base64Encoder; + } + + /** + * Add a workflow template, requires administrator access permissions + * + * @param Workflows\Common\WorkflowDocumentType $workflowDocumentType + * @param string $name + * @param string $description + * @param Workflows\Common\WorkflowAutoExecutionType $workflowAutoExecutionType + * @param string $filename + * @return AddedItemResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/wirkflow_template/bizproc_workflow_template_add.php + */ + 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) + ])); + } + + /** + * 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. + * + * @param int $templateId + * @return DeletedItemResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/wirkflow_template/bizproc_workflow_template_delete.php + */ + public function delete(int $templateId): DeletedItemResult + { + return new DeletedItemResult($this->core->call('bizproc.workflow.template.delete', [ + 'ID' => $templateId + ])); } /** diff --git a/src/Services/Workflows/Workflow/Result/WorkflowKillResult.php b/src/Services/Workflows/Workflow/Result/WorkflowKillResult.php new file mode 100644 index 00000000..4173ee57 --- /dev/null +++ b/src/Services/Workflows/Workflow/Result/WorkflowKillResult.php @@ -0,0 +1,15 @@ +getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Workflow/Service/Workflow.php b/src/Services/Workflows/Workflow/Service/Workflow.php index 7a2abe12..5bb93a35 100644 --- a/src/Services/Workflows/Workflow/Service/Workflow.php +++ b/src/Services/Workflows/Workflow/Service/Workflow.php @@ -12,7 +12,6 @@ use Bitrix24\SDK\Services\Workflows; use Psr\Log\LoggerInterface; - class Workflow extends AbstractService { public Batch $batch; @@ -27,6 +26,22 @@ public function __construct( $this->batch = $batch; } + /** + * 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 + */ + 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. * @@ -35,7 +50,7 @@ public function __construct( * @return Workflows\Workflow\Result\WorkflowTerminationResult * @see https://training.bitrix24.com/rest_help/workflows/workflow/bizproc_workflow_terminate.php */ - public function terminate(string $workflowId, string $message) + 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, @@ -53,44 +68,44 @@ public function terminate(string $workflowId, string $message) * */ public function start( - Workflows\Common\WorkflowDocumentType $workflowDocumentType, - int $bizProcTemplateId, - int $entityId, - array $callParameters = [], - int $smartProcessId = null + Workflows\Common\DocumentType $workflowDocumentType, + int $bizProcTemplateId, + int $entityId, + array $callParameters = [], + int $smartProcessId = null ): Workflows\Workflow\Result\WorkflowInstanceStartResult { $documentId = null; switch ($workflowDocumentType) { - case Workflows\Common\WorkflowDocumentType::crmLead: + case Workflows\Common\DocumentType::crmLead: $documentId = ['crm', $workflowDocumentType->value, sprintf('LEAD_%s', $entityId)]; break; - case Workflows\Common\WorkflowDocumentType::crmCompany: + case Workflows\Common\DocumentType::crmCompany: $documentId = ['crm', $workflowDocumentType->value, sprintf('COMPANY_%s', $entityId)]; break; - case Workflows\Common\WorkflowDocumentType::crmContact: + case Workflows\Common\DocumentType::crmContact: $documentId = ['crm', $workflowDocumentType->value, sprintf('CONTACT_%s', $entityId)]; break; - case Workflows\Common\WorkflowDocumentType::crmDeal: + case Workflows\Common\DocumentType::crmDeal: $documentId = ['crm', $workflowDocumentType->value, sprintf('DEAL_%s', $entityId)]; break; - case Workflows\Common\WorkflowDocumentType::discBizProcDocument: + case Workflows\Common\DocumentType::discBizProcDocument: $documentId = ['disk', $workflowDocumentType->value, $entityId]; break; - case Workflows\Common\WorkflowDocumentType::listBizProcDocumentLists: - case Workflows\Common\WorkflowDocumentType::listBizProcDocument: + case Workflows\Common\DocumentType::listBizProcDocumentLists: + case Workflows\Common\DocumentType::listBizProcDocument: $documentId = ['lists', $workflowDocumentType->value, $entityId]; break; - case Workflows\Common\WorkflowDocumentType::smartProcessDynamic: + 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\WorkflowDocumentType::task: + case Workflows\Common\DocumentType::task: $documentId = ['tasks', $workflowDocumentType->value, $entityId]; break; - case Workflows\Common\WorkflowDocumentType::invoice: + case Workflows\Common\DocumentType::invoice: $documentId = ['tasks', $workflowDocumentType->value, sprintf('SMART_INVOICE_%s', $entityId)]; break; } diff --git a/src/Services/Workflows/WorkflowsServiceBuilder.php b/src/Services/Workflows/WorkflowsServiceBuilder.php index 3489d168..a2ea14e1 100644 --- a/src/Services/Workflows/WorkflowsServiceBuilder.php +++ b/src/Services/Workflows/WorkflowsServiceBuilder.php @@ -4,8 +4,10 @@ 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 { @@ -54,6 +56,11 @@ public function template(): Workflows\Template\Service\Template $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 ); } From 1508d137ea1fe17d18092ca616d7161b207f2046 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 4 May 2024 17:43:02 +0600 Subject: [PATCH 015/138] Add exception handling for empty updates and update service descriptions This commit introduces exception handling for API calls attempting to update records without providing any fields to update. This checks for zero-count field arrays and throws an InvalidArgumentException in such cases. Additionally, service descriptions in the Workflow Templates have been updated for better clarity. Signed-off-by: mesilov --- CHANGELOG.md | 18 +++--- src/Core/ApiLevelErrorHandler.php | 6 ++ .../Workflows/Activity/Service/Activity.php | 4 ++ .../Workflows/Robot/Service/Robot.php | 5 +- .../Workflows/Template/Service/Batch.php | 5 -- .../Workflows/Template/Service/Template.php | 58 +++++++++++++++++++ 6 files changed, 82 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f483087..2f34238e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,11 @@ ## 2.0-beta.3 — 1.05.2024 ### Added - +* add dependencies + * `symfony/console` version `^6 || ^7` + * `symfony/dotenv` version `^6 || ^7` + * `symfony/filesystem` version `^6 || ^7`, + * `symfony/mime` version `^6 || ^7`, * 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 @@ -24,16 +28,14 @@ * `kill` – delete a launched workflow * `start` – launches a workflow * `terminate` – stops an active workflow - * `Template` — 🛠️ WIP + * `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` — 🛠️ WIP * add `WorkflowActivityDocumentType` * add method `Bitrix24\SDK\Core\Credentials\AccessToken::initFromWorkflowRequest` -* add dependencies - * require - * `symfony/console` version `^6 || ^7` - * `symfony/dotenv` version `^6 || ^7` - * `symfony/filesystem` version `^6 || ^7`, - * `symfony/mime` version `^6 || ^7`, * add `\Bitrix24\SDK\Infrastructure\Filesystem\Base64Encoder` for work with base64 encoding * add `\Bitrix24\SDK\Core\Exceptions\FileNotFoundException` if file not found diff --git a/src/Core/ApiLevelErrorHandler.php b/src/Core/ApiLevelErrorHandler.php index 4df6b664..b1f714bc 100644 --- a/src/Core/ApiLevelErrorHandler.php +++ b/src/Core/ApiLevelErrorHandler.php @@ -6,6 +6,7 @@ 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; @@ -85,8 +86,13 @@ private function handleError(array $responseBody, ?string $batchCommandId = null 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'; + } switch ($errorCode) { + 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)); diff --git a/src/Services/Workflows/Activity/Service/Activity.php b/src/Services/Workflows/Activity/Service/Activity.php index 5e1a63b9..00ee1feb 100644 --- a/src/Services/Workflows/Activity/Service/Activity.php +++ b/src/Services/Workflows/Activity/Service/Activity.php @@ -6,6 +6,7 @@ use Bitrix24\SDK\Core\Contracts\CoreInterface; 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; @@ -190,6 +191,9 @@ public function update( 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', [ diff --git a/src/Services/Workflows/Robot/Service/Robot.php b/src/Services/Workflows/Robot/Service/Robot.php index 5188d03b..a68dcbc4 100644 --- a/src/Services/Workflows/Robot/Service/Robot.php +++ b/src/Services/Workflows/Robot/Service/Robot.php @@ -6,6 +6,7 @@ use Bitrix24\SDK\Core\Contracts\CoreInterface; 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; @@ -148,7 +149,9 @@ public function update( 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', [ diff --git a/src/Services/Workflows/Template/Service/Batch.php b/src/Services/Workflows/Template/Service/Batch.php index 8121e292..af3aee34 100644 --- a/src/Services/Workflows/Template/Service/Batch.php +++ b/src/Services/Workflows/Template/Service/Batch.php @@ -5,11 +5,6 @@ namespace Bitrix24\SDK\Services\Workflows\Template\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 diff --git a/src/Services/Workflows/Template/Service/Template.php b/src/Services/Workflows/Template/Service/Template.php index fe8af1e8..1cf1c928 100644 --- a/src/Services/Workflows/Template/Service/Template.php +++ b/src/Services/Workflows/Template/Service/Template.php @@ -6,9 +6,11 @@ use Bitrix24\SDK\Core\Contracts\CoreInterface; 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; @@ -62,6 +64,62 @@ public function add( ])); } + /** + * 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. + * + * @param int $templateId + * @param Workflows\Common\WorkflowDocumentType|null $workflowDocumentType + * @param string|null $name + * @param string|null $description + * @param Workflows\Common\WorkflowAutoExecutionType|null $workflowAutoExecutionType + * @param string|null $filename + * @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 + */ + 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. * From ecb19e13bc51ed623d77227deb78fe6df089a871 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 5 May 2024 02:04:26 +0600 Subject: [PATCH 016/138] Add nesbot/carbon dependency Introduced "nesbot/carbon" version 3.3.* as a new dependency in composer.json. Updated CHANGELOG.md to reflect the added dependency. Signed-off-by: mesilov --- CHANGELOG.md | 5 +++-- composer.json | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f34238e..2019c0e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,9 @@ * add dependencies * `symfony/console` version `^6 || ^7` * `symfony/dotenv` version `^6 || ^7` - * `symfony/filesystem` version `^6 || ^7`, - * `symfony/mime` version `^6 || ^7`, + * `symfony/filesystem` version `^6 || ^7` + * `symfony/mime` version `^6 || ^7` + * `nesbot/carbon` version `3.3.*` * 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 diff --git a/composer.json b/composer.json index 8c93e362..ee3b9e22 100644 --- a/composer.json +++ b/composer.json @@ -28,6 +28,7 @@ "psr/log": "^2 || ^3", "fig/http-message-util": "1.1.*", "ramsey/uuid": "^3 ||^4", + "nesbot/carbon": "3.3.*", "moneyphp/money": "^3 || ^4", "symfony/http-client": "^6 || ^7", "symfony/console": "^6 || ^7", From 6a376298b473b1e32895cbcc538ed2e966c88ec4 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 5 May 2024 02:05:44 +0600 Subject: [PATCH 017/138] Add workflow task service and related classes This commit introduces the task service for workflows along with the relevant types and results. WorkflowTaskStatusType, WorkflowTaskUserStatusType, and WorkflowTaskCompleteStatusType enums are added for various status types. WorkflowTasksResult and WorkflowTaskItemResult classes are created to handle task results. The ServiceBuilder has been updated to produce the new task service. Signed-off-by: mesilov --- .../Common/WorkflowTaskActivityType.php | 13 +++ .../Common/WorkflowTaskCompleteStatusType.php | 13 +++ .../Common/WorkflowTaskStatusType.php | 14 +++ .../Common/WorkflowTaskUserStatusType.php | 13 +++ .../Task/Result/WorkflowTaskItemResult.php | 88 +++++++++++++++++++ .../Task/Result/WorkflowTasksResult.php | 25 ++++++ src/Services/Workflows/Task/Service/Batch.php | 17 ++++ src/Services/Workflows/Task/Service/Task.php | 60 +++++++++++++ .../Workflows/WorkflowsServiceBuilder.php | 13 +++ 9 files changed, 256 insertions(+) create mode 100644 src/Services/Workflows/Common/WorkflowTaskActivityType.php create mode 100644 src/Services/Workflows/Common/WorkflowTaskCompleteStatusType.php create mode 100644 src/Services/Workflows/Common/WorkflowTaskStatusType.php create mode 100644 src/Services/Workflows/Common/WorkflowTaskUserStatusType.php create mode 100644 src/Services/Workflows/Task/Result/WorkflowTaskItemResult.php create mode 100644 src/Services/Workflows/Task/Result/WorkflowTasksResult.php create mode 100644 src/Services/Workflows/Task/Service/Batch.php create mode 100644 src/Services/Workflows/Task/Service/Task.php diff --git a/src/Services/Workflows/Common/WorkflowTaskActivityType.php b/src/Services/Workflows/Common/WorkflowTaskActivityType.php new file mode 100644 index 00000000..e7fba294 --- /dev/null +++ b/src/Services/Workflows/Common/WorkflowTaskActivityType.php @@ -0,0 +1,13 @@ +data[$offset]; + case 'DOCUMENT_ID': + if ($this->data[$offset] !== '') { + return (int)substr($this->data[$offset], strrpos($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..f1fd9113 --- /dev/null +++ b/src/Services/Workflows/Task/Result/WorkflowTasksResult.php @@ -0,0 +1,25 @@ +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..ab408b62 --- /dev/null +++ b/src/Services/Workflows/Task/Service/Batch.php @@ -0,0 +1,17 @@ +batch = $batch; + } + + /** + * 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 $order + * @param array $filter + * @param 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} $select + * @return WorkflowTasksResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/workflows_tasks/bizproc_task_list.php + */ + public function list( + array $order = ['ID' => 'DESC'], + array $filter = [], + array $select = ['ID', 'WORKFLOW_ID', 'DOCUMENT_NAME', 'NAME']) + { + 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/WorkflowsServiceBuilder.php b/src/Services/Workflows/WorkflowsServiceBuilder.php index a2ea14e1..cb9d84a5 100644 --- a/src/Services/Workflows/WorkflowsServiceBuilder.php +++ b/src/Services/Workflows/WorkflowsServiceBuilder.php @@ -50,6 +50,19 @@ public function activity(): Workflows\Activity\Service\Activity 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__])) { From 5e5a7c40acd7db247ae41a5a5b53953763d85e7c Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 5 May 2024 17:31:12 +0600 Subject: [PATCH 018/138] Update PHPStan configuration and refactor Task service The commit mainly updates the PHPStan configuration in the Makefile and phpstan.neon.dist, increasing memory limit and setting parallel processing parameters. It also refactors the Task service by expanding function parameter arrays into multiple lines for improved readability and maintainability. Signed-off-by: mesilov --- Makefile | 2 +- phpstan.neon.dist | 8 +++- src/Services/Workflows/Task/Service/Task.php | 48 ++++++++++++++++++-- 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 6e31904d..0b5d2a8c 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ default: @egrep -e '^\S+' ./Makefile | grep -v default | sed -r 's/://' | sed -r 's/^/ - /' phpstan: - vendor/bin/phpstan analyse + vendor/bin/phpstan --memory-limit=1G analyse test-unit: vendor/bin/phpunit --testsuite unit_tests \ No newline at end of file diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 7e4f8de6..337e4f57 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -3,4 +3,10 @@ parameters: paths: - src/ bootstrapFiles: - - tests/bootstrap.php \ No newline at end of file + - tests/bootstrap.php + parallel: + jobSize: 20 + maximumNumberOfProcesses: 8 + minimumNumberOfJobsPerProcess: 2 + editorUrlTitle: '%%relFile%%:%%line%%' + editorUrl: 'phpstorm://open?file=%%file%%&line=%%line%%' \ No newline at end of file diff --git a/src/Services/Workflows/Task/Service/Task.php b/src/Services/Workflows/Task/Service/Task.php index e8228f5b..23503cb0 100644 --- a/src/Services/Workflows/Task/Service/Task.php +++ b/src/Services/Workflows/Task/Service/Task.php @@ -39,8 +39,50 @@ public function __construct( * To request personal tasks, non-administrator should not specify filter for USER_ID * * @param array $order - * @param array $filter - * @param 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} $select + * @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 @@ -49,7 +91,7 @@ public function __construct( public function list( array $order = ['ID' => 'DESC'], array $filter = [], - array $select = ['ID', 'WORKFLOW_ID', 'DOCUMENT_NAME', 'NAME']) + array $select = ['ID', 'WORKFLOW_ID', 'DOCUMENT_NAME', 'NAME']): WorkflowTasksResult { return new WorkflowTasksResult($this->core->call('bizproc.task.list', [ 'SELECT' => $select, From 2319b7c5576a0a13b9b26b00a3dc1cea94e53498 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 6 May 2024 02:43:25 +0600 Subject: [PATCH 019/138] Add support for completing workflow tasks A new feature has been introduced to handle completion of workflow tasks. This included the addition of a new 'complete' method in the workflows task service, the WorkflowTaskAlreadyCompletedException for handling task already completed errors, and the WorkflowTaskCompleteResult for managing the task completion result. The CHANGELOG and documentation have been updated accordingly. Signed-off-by: mesilov --- CHANGELOG.md | 5 ++- src/Core/ApiLevelErrorHandler.php | 3 ++ .../WorkflowTaskAlreadyCompletedException.php | 9 ++++++ .../Result/WorkflowTaskCompleteResult.php | 15 +++++++++ src/Services/Workflows/Task/Service/Task.php | 32 +++++++++++++++++-- 5 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 src/Services/Workflows/Exceptions/WorkflowTaskAlreadyCompletedException.php create mode 100644 src/Services/Workflows/Task/Result/WorkflowTaskCompleteResult.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 2019c0e5..93e34a0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 2.0-beta.3 — 1.05.2024 ### Added + * add dependencies * `symfony/console` version `^6 || ^7` * `symfony/dotenv` version `^6 || ^7` @@ -34,7 +35,9 @@ * `delete` – delete workflow template * `list` – returns list of workflow templates * `update` – update workflow template - * `Tasks` — 🛠️ WIP + * `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 `\Bitrix24\SDK\Infrastructure\Filesystem\Base64Encoder` for work with base64 encoding diff --git a/src/Core/ApiLevelErrorHandler.php b/src/Core/ApiLevelErrorHandler.php index b1f714bc..a580f8d4 100644 --- a/src/Core/ApiLevelErrorHandler.php +++ b/src/Core/ApiLevelErrorHandler.php @@ -12,6 +12,7 @@ use Bitrix24\SDK\Core\Exceptions\QueryLimitExceededException; 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; /** @@ -91,6 +92,8 @@ private function handleError(array $responseBody, ?string $batchCommandId = null } 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': diff --git a/src/Services/Workflows/Exceptions/WorkflowTaskAlreadyCompletedException.php b/src/Services/Workflows/Exceptions/WorkflowTaskAlreadyCompletedException.php new file mode 100644 index 00000000..83a611ad --- /dev/null +++ b/src/Services/Workflows/Exceptions/WorkflowTaskAlreadyCompletedException.php @@ -0,0 +1,9 @@ +getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Services/Workflows/Task/Service/Task.php b/src/Services/Workflows/Task/Service/Task.php index 23503cb0..c9e414e7 100644 --- a/src/Services/Workflows/Task/Service/Task.php +++ b/src/Services/Workflows/Task/Service/Task.php @@ -6,15 +6,15 @@ use Bitrix24\SDK\Core\Contracts\CoreInterface; 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\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 DateTimeInterface; use Psr\Log\LoggerInterface; use Bitrix24\SDK\Services\Workflows\Task\Result\WorkflowTasksResult; @@ -32,6 +32,34 @@ public function __construct( $this->batch = $batch; } + /** + * 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. + * + * @param int $taskId + * @param WorkflowTaskCompleteStatusType $status + * @param string $comment + * @param array|null $taskFields + * @return WorkflowTaskCompleteResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/workflows/workflows_tasks/bizproc_task_complete.php + */ + 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 * From 19feebe68c57f029adabda899304a1381d44580a Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 24 May 2024 00:48:56 +0600 Subject: [PATCH 020/138] Add Rector for static code analysis Added Rector to the project for static code analysis and cleaning. The Makefile has been updated with a linter for Rector, and a linter fixer has been provided. Additionally, 'rector/rector' was added to the composer.json dependencies. Signed-off-by: mesilov --- Makefile | 4 ++++ composer.json | 3 ++- rector.php | 21 +++++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 rector.php diff --git a/Makefile b/Makefile index 0b5d2a8c..22233389 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,10 @@ default: phpstan: vendor/bin/phpstan --memory-limit=1G analyse +lint-rector: + vendor/bin/rector process --dry-run +lint-rector-fix: + vendor/bin/rector process test-unit: vendor/bin/phpunit --testsuite unit_tests \ No newline at end of file diff --git a/composer.json b/composer.json index ee3b9e22..bd2af157 100644 --- a/composer.json +++ b/composer.json @@ -47,7 +47,8 @@ "symfony/debug-bundle": "7.0.*", "symfony/stopwatch": "7.0.*", "roave/security-advisories": "dev-master", - "fakerphp/faker": "1.23.*" + "fakerphp/faker": "1.23.*", + "rector/rector": "^1.0" }, "autoload": { "psr-4": { diff --git a/rector.php b/rector.php new file mode 100644 index 00000000..5bd131ec --- /dev/null +++ b/rector.php @@ -0,0 +1,21 @@ +withPaths([ + __DIR__ . '/src/Services/Workflows', + ]) + ->withSets( + [DowngradeLevelSetList::DOWN_TO_PHP_82] + ) + ->withPhpSets( + php82: true // 8.2 + ) + ->withRules([ + AddVoidReturnTypeWhereNoReturnRector::class, + ]); \ No newline at end of file From 0e2e38aa31e3b3873775bb48704e87a575c2bcd1 Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 24 May 2024 01:02:10 +0600 Subject: [PATCH 021/138] Refactor code for clarity and robustness This commit includes a few changes, mainly focused on code cleanup. It removes redundant properties and type conversions while enhancing string manipulations for better robustness. It also simplifies method signatures by removing unnecessary parameters, making the code more concise and easier to read. Signed-off-by: mesilov --- .../Workflows/Activity/Service/Activity.php | 14 ++++------- .../Workflows/Event/Service/Event.php | 9 +------- .../Workflows/Robot/Service/Robot.php | 20 +--------------- .../Task/Result/WorkflowTaskItemResult.php | 2 +- src/Services/Workflows/Task/Service/Task.php | 10 +------- .../Workflows/Template/Service/Template.php | 23 ++----------------- .../Result/WorkflowInstanceItemResult.php | 2 +- .../Workflows/Workflow/Service/Workflow.php | 10 +------- 8 files changed, 12 insertions(+), 78 deletions(-) diff --git a/src/Services/Workflows/Activity/Service/Activity.php b/src/Services/Workflows/Activity/Service/Activity.php index 00ee1feb..6de4f601 100644 --- a/src/Services/Workflows/Activity/Service/Activity.php +++ b/src/Services/Workflows/Activity/Service/Activity.php @@ -12,29 +12,25 @@ 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; class Activity extends AbstractService { - public Batch $batch; - public function __construct( - Batch $batch, + public Batch $batch, CoreInterface $core, LoggerInterface $log ) { parent::__construct($core, $log); - $this->batch = $batch; } /** * This method records data in the workflow log. - * @param string $eventToken - * @param string $message - * @return Workflows\Activity\Result\AddedMessageToLogResult + * @return AddedMessageToLogResult * @throws BaseException * @throws TransportException * @see https://training.bitrix24.com/rest_help/workflows/app_activities/bizproc_activity_list.php @@ -111,14 +107,12 @@ public function add( /** * This method deletes an activity. * - * @param string $activityCode * @return DeletedItemResult * @throws BaseException * @throws TransportException * @see https://training.bitrix24.com/rest_help/workflows/app_activities/bizproc_activity_delete.php */ - public - function delete(string $activityCode): DeletedItemResult + public function delete(string $activityCode): DeletedItemResult { return new DeletedItemResult( $this->core->call('bizproc.activity.delete', [ diff --git a/src/Services/Workflows/Event/Service/Event.php b/src/Services/Workflows/Event/Service/Event.php index 28309ae3..a36958b3 100644 --- a/src/Services/Workflows/Event/Service/Event.php +++ b/src/Services/Workflows/Event/Service/Event.php @@ -13,25 +13,18 @@ class Event extends AbstractService { - public Batch $batch; - public function __construct( - Batch $batch, + public Batch $batch, CoreInterface $core, LoggerInterface $log ) { parent::__construct($core, $log); - $this->batch = $batch; } /** * returns output parameters to an activity. Parameters are specified in the activity description. * - * @param string $eventToken - * @param array $returnValues - * @param string|null $logMessage - * * @return Workflows\Event\Result\EventSendResult * @throws BaseException * @throws TransportException diff --git a/src/Services/Workflows/Robot/Service/Robot.php b/src/Services/Workflows/Robot/Service/Robot.php index a68dcbc4..c77e7dd8 100644 --- a/src/Services/Workflows/Robot/Service/Robot.php +++ b/src/Services/Workflows/Robot/Service/Robot.php @@ -19,29 +19,18 @@ class Robot extends AbstractService { - public Batch $batch; - public function __construct( - Batch $batch, + public Batch $batch, CoreInterface $core, LoggerInterface $log ) { parent::__construct($core, $log); - $this->batch = $batch; } /** * Registers new automation rule. * - * @param string $code - * @param string $handlerUrl - * @param int $b24AuthUserId - * @param array $localizedRobotName - * @param bool $isUseSubscription - * @param array $properties - * @param bool $isUsePlacement - * @param array $returnProperties * * @return AddedRobotResult * @throws BaseException @@ -86,7 +75,6 @@ public function list(): Workflows\Robot\Result\WorkflowRobotsResult /** * This method deletes registered automation rule. * - * @param string $robotCode * @return DeletedItemResult * @throws BaseException * @throws TransportException @@ -103,14 +91,8 @@ public function delete(string $robotCode): DeletedItemResult /** * updates fields of automation rules * - * @param string $code - * @param string|null $handlerUrl - * @param int|null $b24AuthUserId - * @param array|null $localizedRobotName * @param bool $isUseSubscription - * @param array|null $properties * @param bool $isUsePlacement - * @param array|null $returnProperties * @return UpdateRobotResult * @throws BaseException * @throws TransportException diff --git a/src/Services/Workflows/Task/Result/WorkflowTaskItemResult.php b/src/Services/Workflows/Task/Result/WorkflowTaskItemResult.php index 2bd8b68f..b3588db0 100644 --- a/src/Services/Workflows/Task/Result/WorkflowTaskItemResult.php +++ b/src/Services/Workflows/Task/Result/WorkflowTaskItemResult.php @@ -47,7 +47,7 @@ public function __get($offset) return (int)$this->data[$offset]; case 'DOCUMENT_ID': if ($this->data[$offset] !== '') { - return (int)substr($this->data[$offset], strrpos($this->data[$offset], '_') + 1); + return (int)substr((string) $this->data[$offset], strrpos((string) $this->data[$offset], '_') + 1); } return null; case 'MODIFIED': diff --git a/src/Services/Workflows/Task/Service/Task.php b/src/Services/Workflows/Task/Service/Task.php index c9e414e7..7d209803 100644 --- a/src/Services/Workflows/Task/Service/Task.php +++ b/src/Services/Workflows/Task/Service/Task.php @@ -20,16 +20,13 @@ class Task extends AbstractService { - public Batch $batch; - public function __construct( - Batch $batch, + public Batch $batch, CoreInterface $core, LoggerInterface $log ) { parent::__construct($core, $log); - $this->batch = $batch; } /** @@ -41,10 +38,6 @@ public function __construct( * 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. * - * @param int $taskId - * @param WorkflowTaskCompleteStatusType $status - * @param string $comment - * @param array|null $taskFields * @return WorkflowTaskCompleteResult * @throws BaseException * @throws TransportException @@ -66,7 +59,6 @@ public function complete(int $taskId, WorkflowTaskCompleteStatusType $status, st * 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 $order * @param array|array{ * ID?:int, * WORKFLOW_ID?:string, diff --git a/src/Services/Workflows/Template/Service/Template.php b/src/Services/Workflows/Template/Service/Template.php index 1cf1c928..2d62f485 100644 --- a/src/Services/Workflows/Template/Service/Template.php +++ b/src/Services/Workflows/Template/Service/Template.php @@ -19,29 +19,19 @@ class Template extends AbstractService { - public Batch $batch; - private Base64Encoder $base64Encoder; - public function __construct( - Batch $batch, + public Batch $batch, CoreInterface $core, - Base64Encoder $base64Encoder, + private readonly Base64Encoder $base64Encoder, LoggerInterface $log ) { parent::__construct($core, $log); - $this->batch = $batch; - $this->base64Encoder = $base64Encoder; } /** * Add a workflow template, requires administrator access permissions * - * @param Workflows\Common\WorkflowDocumentType $workflowDocumentType - * @param string $name - * @param string $description - * @param Workflows\Common\WorkflowAutoExecutionType $workflowAutoExecutionType - * @param string $filename * @return AddedItemResult * @throws BaseException * @throws TransportException @@ -70,12 +60,6 @@ public function add( * 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. * - * @param int $templateId - * @param Workflows\Common\WorkflowDocumentType|null $workflowDocumentType - * @param string|null $name - * @param string|null $description - * @param Workflows\Common\WorkflowAutoExecutionType|null $workflowAutoExecutionType - * @param string|null $filename * @return UpdatedItemResult * @throws BaseException * @throws TransportException @@ -126,7 +110,6 @@ public function update( * 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. * - * @param int $templateId * @return DeletedItemResult * @throws BaseException * @throws TransportException @@ -141,8 +124,6 @@ public function delete(int $templateId): DeletedItemResult /** * The method bizproc.workflow.template.list returns list of workflow templates, specified for a site. This method requires administrator access permissions. - * @param array $select - * @param array $filter * @return Workflows\Template\Result\WorkflowTemplatesResult * @throws BaseException * @throws TransportException diff --git a/src/Services/Workflows/Workflow/Result/WorkflowInstanceItemResult.php b/src/Services/Workflows/Workflow/Result/WorkflowInstanceItemResult.php index 29375da0..d5df6c77 100644 --- a/src/Services/Workflows/Workflow/Result/WorkflowInstanceItemResult.php +++ b/src/Services/Workflows/Workflow/Result/WorkflowInstanceItemResult.php @@ -31,7 +31,7 @@ public function __get($offset) case 'DOCUMENT_ID': if ($this->data[$offset] !== '') { // "DEAL_158310" - return (int)substr($this->data[$offset], strpos($this->data[$offset], '_')+1); + return (int)substr((string) $this->data[$offset], strpos((string) $this->data[$offset], '_')+1); } return null; case 'MODIFIED': diff --git a/src/Services/Workflows/Workflow/Service/Workflow.php b/src/Services/Workflows/Workflow/Service/Workflow.php index 5bb93a35..78e38c06 100644 --- a/src/Services/Workflows/Workflow/Service/Workflow.php +++ b/src/Services/Workflows/Workflow/Service/Workflow.php @@ -14,16 +14,13 @@ class Workflow extends AbstractService { - public Batch $batch; - public function __construct( - Batch $batch, + public Batch $batch, CoreInterface $core, LoggerInterface $log ) { parent::__construct($core, $log); - $this->batch = $batch; } /** @@ -45,8 +42,6 @@ public function kill(string $workflowId): Workflows\Workflow\Result\WorkflowKill /** * Stops an active workflow. * - * @param string $workflowId - * @param string $message * @return Workflows\Workflow\Result\WorkflowTerminationResult * @see https://training.bitrix24.com/rest_help/workflows/workflow/bizproc_workflow_terminate.php */ @@ -124,9 +119,6 @@ public function start( /** * returns list of launched workflows * - * @param array $select - * @param array $order - * @param array $filter * @return Workflows\Workflow\Result\WorkflowInstancesResult * @throws BaseException * @throws TransportException From 757a805d987a09d290244f3f58eba08cfd0dda39 Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 24 May 2024 01:07:58 +0600 Subject: [PATCH 022/138] Add Rector to improve code quality and speed up releases In this commit, Rector was added to the project to enhance the quality of the code and expedite the release cycle. With the help of Rector, regular code refactoring tasks get simplified and can be performed more swiftly, thus shortening the overall time for releases. Signed-off-by: mesilov --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93e34a0a..b46aa209 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,7 @@ * add method `Bitrix24\SDK\Core\Credentials\AccessToken::initFromWorkflowRequest` * add `\Bitrix24\SDK\Infrastructure\Filesystem\Base64Encoder` for work with base64 encoding * add `\Bitrix24\SDK\Core\Exceptions\FileNotFoundException` if file not found +* add [Rector](https://github.com/rectorphp/rector) for improve code quality and speed up releases cycle ## 2.0-beta.2 — 1.04.2024 From a46897bb0f5914aebe11cb1e07296e3ff727d987 Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 24 May 2024 01:43:49 +0600 Subject: [PATCH 023/138] Add new scope Signed-off-by: mesilov --- src/Core/Credentials/Scope.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Core/Credentials/Scope.php b/src/Core/Credentials/Scope.php index d028e1e7..38458bdb 100644 --- a/src/Core/Credentials/Scope.php +++ b/src/Core/Credentials/Scope.php @@ -12,9 +12,14 @@ class Scope * @var string[] */ protected array $availableScope = [ + 'ai_admin', + 'appform', + 'baas', 'bizproc', 'biconnector', 'calendar', + 'calendarmobile', + 'catalogmobile', 'call', 'cashbox', 'catalog', @@ -32,6 +37,8 @@ class Scope 'im', 'imbot', 'imopenlines', + 'im.import', + 'imconnector', 'intranet', 'landing', 'landing_cloud', @@ -40,6 +47,7 @@ class Scope 'mailservice', 'messageservice', 'mobile', + 'notifications', 'pay_system', 'placement', 'pull', @@ -54,6 +62,7 @@ class Scope 'task', 'tasks', 'tasks_extended', + 'tasksmobile', 'telephony', 'timeman', 'user', From fe37bee09a8c9441b8eb4bfefc0f06c017493619 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 25 May 2024 02:20:41 +0600 Subject: [PATCH 024/138] Add workflow auth Signed-off-by: mesilov --- src/Application/ApplicationStatus.php | 35 +++++--------- src/Core/Credentials/Endpoints.php | 41 ++++++++++++++++ .../Workflows/Common/WorkflowDocumentId.php | 26 ++++++++++ .../Workflows/Common/WorkflowDocumentType.php | 5 ++ .../Workflows/Workflow/Request/Auth.php | 48 +++++++++++++++++++ .../Request/IncomingWorkflowRequest.php | 48 +++++++++++++++++++ 6 files changed, 179 insertions(+), 24 deletions(-) create mode 100644 src/Core/Credentials/Endpoints.php create mode 100644 src/Services/Workflows/Common/WorkflowDocumentId.php create mode 100644 src/Services/Workflows/Workflow/Request/Auth.php create mode 100644 src/Services/Workflows/Workflow/Request/IncomingWorkflowRequest.php diff --git a/src/Application/ApplicationStatus.php b/src/Application/ApplicationStatus.php index fc65ebc4..94662f48 100644 --- a/src/Application/ApplicationStatus.php +++ b/src/Application/ApplicationStatus.php @@ -24,30 +24,17 @@ class ApplicationStatus */ public function __construct(string $statusShortCode) { - switch ($statusShortCode) { - case self::STATUS_SHORT_FREE: - $this->statusCode = 'free'; - break; - case self::STATUS_SHORT_DEMO: - $this->statusCode = 'demo'; - break; - case self::STATUS_SHORT_TRIAL: - $this->statusCode = 'trial'; - break; - case self::STATUS_SHORT_PAID: - $this->statusCode = 'paid'; - break; - case self::STATUS_SHORT_LOCAL: - $this->statusCode = 'local'; - break; - case self::STATUS_SHORT_SUBSCRIPTION: - $this->statusCode = 'subscription'; - break; - default: - throw new InvalidArgumentException( - sprintf('unknown application status code %s', $statusShortCode) - ); - } + $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) + ), + }; } /** diff --git a/src/Core/Credentials/Endpoints.php b/src/Core/Credentials/Endpoints.php new file mode 100644 index 00000000..f88a3da7 --- /dev/null +++ b/src/Core/Credentials/Endpoints.php @@ -0,0 +1,41 @@ +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 index 0d8aa25c..759621b6 100644 --- a/src/Services/Workflows/Common/WorkflowDocumentType.php +++ b/src/Services/Workflows/Common/WorkflowDocumentType.php @@ -14,6 +14,11 @@ public function __construct( { } + 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]; diff --git a/src/Services/Workflows/Workflow/Request/Auth.php b/src/Services/Workflows/Workflow/Request/Auth.php new file mode 100644 index 00000000..cbc863b0 --- /dev/null +++ b/src/Services/Workflows/Workflow/Request/Auth.php @@ -0,0 +1,48 @@ +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['is_use_subscription'] === 'Y' ? true : false, + $data['timeout_duration'], + $data['ts'], + Auth::initFromArray($data['auth']) + ); + } +} \ No newline at end of file From 0f9e84c773e11467274bb97ce130c5bfbe1e9757 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 25 May 2024 02:35:17 +0600 Subject: [PATCH 025/138] Fix type errors Signed-off-by: mesilov --- src/Services/Workflows/Workflow/Request/Auth.php | 4 ++-- .../Workflows/Workflow/Request/IncomingWorkflowRequest.php | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Services/Workflows/Workflow/Request/Auth.php b/src/Services/Workflows/Workflow/Request/Auth.php index cbc863b0..4d24e395 100644 --- a/src/Services/Workflows/Workflow/Request/Auth.php +++ b/src/Services/Workflows/Workflow/Request/Auth.php @@ -39,10 +39,10 @@ public static function initFromArray(array $auth): self Scope::initFromString($auth['scope']), ApplicationStatus::initFromString($auth['status']), $auth['application_token'], - $auth['expires_in'], + (int)$auth['expires_in'], $auth['domain'], $auth['member_id'], - $auth['user_id'] + (int)$auth['user_id'] ); } } \ No newline at end of file diff --git a/src/Services/Workflows/Workflow/Request/IncomingWorkflowRequest.php b/src/Services/Workflows/Workflow/Request/IncomingWorkflowRequest.php index 01ab589a..da012a34 100644 --- a/src/Services/Workflows/Workflow/Request/IncomingWorkflowRequest.php +++ b/src/Services/Workflows/Workflow/Request/IncomingWorkflowRequest.php @@ -39,9 +39,9 @@ public static function initFromRequest(Request $request): self WorkflowDocumentType::initFromArray($data['document_type']), $data['event_token'], $data['properties'], - $data['is_use_subscription'] === 'Y' ? true : false, - $data['timeout_duration'], - $data['ts'], + $data['use_subscription'] === 'Y' ? true : false, + (int)$data['timeout_duration'], + (int)$data['ts'], Auth::initFromArray($data['auth']) ); } From 248016c7977914564aa478aef55dd5b93f97b400 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 26 May 2024 23:14:46 +0600 Subject: [PATCH 026/138] Add IncomingRobotRequest.php and IncomingWorkflowRequest.php Signed-off-by: mesilov --- CHANGELOG.md | 2 + .../{Workflow/Request => Common}/Auth.php | 2 +- .../Robot/Request/IncomingRobotRequest.php | 49 +++++++++++++++++++ .../Request/IncomingWorkflowRequest.php | 1 + 4 files changed, 53 insertions(+), 1 deletion(-) rename src/Services/Workflows/{Workflow/Request => Common}/Auth.php (95%) create mode 100644 src/Services/Workflows/Robot/Request/IncomingRobotRequest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index b46aa209..98babba2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,8 @@ * add method `Bitrix24\SDK\Core\Credentials\AccessToken::initFromWorkflowRequest` * add `\Bitrix24\SDK\Infrastructure\Filesystem\Base64Encoder` for work with base64 encoding * add `\Bitrix24\SDK\Core\Exceptions\FileNotFoundException` if file not found +* add `IncomingRobotRequest` wrapper for data from crm-robot request +* add `IncomingWorkflowRequest` wrapper for data from biz proc activity request * add [Rector](https://github.com/rectorphp/rector) for improve code quality and speed up releases cycle ## 2.0-beta.2 — 1.04.2024 diff --git a/src/Services/Workflows/Workflow/Request/Auth.php b/src/Services/Workflows/Common/Auth.php similarity index 95% rename from src/Services/Workflows/Workflow/Request/Auth.php rename to src/Services/Workflows/Common/Auth.php index 4d24e395..1c1bfde9 100644 --- a/src/Services/Workflows/Workflow/Request/Auth.php +++ b/src/Services/Workflows/Common/Auth.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Services\Workflows\Workflow\Request; +namespace Bitrix24\SDK\Services\Workflows\Common; use Bitrix24\SDK\Application\ApplicationStatus; use Bitrix24\SDK\Core\Credentials\AccessToken; diff --git a/src/Services/Workflows/Robot/Request/IncomingRobotRequest.php b/src/Services/Workflows/Robot/Request/IncomingRobotRequest.php new file mode 100644 index 00000000..679ad196 --- /dev/null +++ b/src/Services/Workflows/Robot/Request/IncomingRobotRequest.php @@ -0,0 +1,49 @@ +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/Request/IncomingWorkflowRequest.php b/src/Services/Workflows/Workflow/Request/IncomingWorkflowRequest.php index da012a34..bfde824f 100644 --- a/src/Services/Workflows/Workflow/Request/IncomingWorkflowRequest.php +++ b/src/Services/Workflows/Workflow/Request/IncomingWorkflowRequest.php @@ -5,6 +5,7 @@ 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; From e2f001a88a19568a2e1a2468eb079823d473400d Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 26 May 2024 23:35:17 +0600 Subject: [PATCH 027/138] update changelog Signed-off-by: mesilov --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98babba2..356635b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,10 @@ * add `IncomingWorkflowRequest` wrapper for data from biz proc activity request * add [Rector](https://github.com/rectorphp/rector) for improve code quality and speed up releases cycle +### Changed +* update scope `telephony`, scope fully rewritten + + ## 2.0-beta.2 — 1.04.2024 ### Changed From 04027d62eb5be8271f7a4dd0aa8569335eccd722 Mon Sep 17 00:00:00 2001 From: mesilov Date: Tue, 28 May 2024 01:46:26 +0600 Subject: [PATCH 028/138] rewrite telephony scope Signed-off-by: mesilov --- src/Services/Telephony/Common/CallType.php | 123 ------- .../Telephony/Common/CrmEntityType.php | 106 ------ .../Common/StatusSipCodeInterface.php | 100 ------ .../Common/StatusSipRegistrations.php | 83 ----- src/Services/Telephony/Common/TypeAtc.php | 63 ---- .../Telephony/Requests/Events/Auth.php | 41 --- .../Events/OnExternalCallBackStart.php | 60 ---- .../Events/OnExternalCallStart/CallData.php | 42 --- .../OnExternalCallStart.php | 30 -- .../Events/OnVoximplantCallEnd/CallData.php | 68 ---- .../OnVoximplantCallEnd.php | 35 -- .../Events/OnVoximplantCallInit/CallData.php | 35 -- .../OnVoximplantCallInit.php | 32 -- .../Events/OnVoximplantCallStart/CallData.php | 28 -- .../OnVoximplantCallStart.php | 29 -- .../Result/CallAttachTranscriptionResult.php | 30 -- .../Result/ExternalCallFinishItemResult.php | 46 --- .../Result/ExternalCallFinishResult.php | 29 -- .../Result/ExternalCallHideResult.php | 31 -- .../Result/ExternalCallRecordResult.php | 28 -- .../Result/ExternalCallRegisterItemResult.php | 40 --- .../Result/ExternalCallRegisterResult.php | 30 -- ...xternalCallSearchCrmEntitiesItemResult.php | 28 -- .../ExternalCallSearchCrmEntitiesResult.php | 34 -- .../Result/ExternalCallShowResult.php | 34 -- .../Result/ExternalLineAddResult.php | 31 -- .../Result/ExternalLineDeleteResult.php | 21 -- .../Result/ExternalLineItemResult.php | 26 -- .../Result/ExternalLineUpdateResult.php | 29 -- .../Telephony/Result/ExternalLinesResult.php | 33 -- .../Services/Telephony/Service/CallTest.php | 139 -------- .../Telephony/Service/ExternalCallTest.php | 308 ------------------ .../Telephony/Service/ExternalLineTest.php | 110 ------- .../Service/SearchCrmEntitiesTest.php | 201 ------------ .../Service/assets/test-phone-record.mp3 | Bin 160954 -> 0 bytes 35 files changed, 2103 deletions(-) delete mode 100644 src/Services/Telephony/Common/CallType.php delete mode 100644 src/Services/Telephony/Common/CrmEntityType.php delete mode 100644 src/Services/Telephony/Common/StatusSipCodeInterface.php delete mode 100644 src/Services/Telephony/Common/StatusSipRegistrations.php delete mode 100644 src/Services/Telephony/Common/TypeAtc.php delete mode 100644 src/Services/Telephony/Requests/Events/Auth.php delete mode 100644 src/Services/Telephony/Requests/Events/OnExternalCallBackStart.php delete mode 100644 src/Services/Telephony/Requests/Events/OnExternalCallStart/CallData.php delete mode 100644 src/Services/Telephony/Requests/Events/OnExternalCallStart/OnExternalCallStart.php delete mode 100644 src/Services/Telephony/Requests/Events/OnVoximplantCallEnd/CallData.php delete mode 100644 src/Services/Telephony/Requests/Events/OnVoximplantCallEnd/OnVoximplantCallEnd.php delete mode 100644 src/Services/Telephony/Requests/Events/OnVoximplantCallInit/CallData.php delete mode 100644 src/Services/Telephony/Requests/Events/OnVoximplantCallInit/OnVoximplantCallInit.php delete mode 100644 src/Services/Telephony/Requests/Events/OnVoximplantCallStart/CallData.php delete mode 100644 src/Services/Telephony/Requests/Events/OnVoximplantCallStart/OnVoximplantCallStart.php delete mode 100644 src/Services/Telephony/Result/CallAttachTranscriptionResult.php delete mode 100644 src/Services/Telephony/Result/ExternalCallFinishItemResult.php delete mode 100644 src/Services/Telephony/Result/ExternalCallFinishResult.php delete mode 100644 src/Services/Telephony/Result/ExternalCallHideResult.php delete mode 100644 src/Services/Telephony/Result/ExternalCallRecordResult.php delete mode 100644 src/Services/Telephony/Result/ExternalCallRegisterItemResult.php delete mode 100644 src/Services/Telephony/Result/ExternalCallRegisterResult.php delete mode 100644 src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesItemResult.php delete mode 100644 src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php delete mode 100644 src/Services/Telephony/Result/ExternalCallShowResult.php delete mode 100644 src/Services/Telephony/Result/ExternalLineAddResult.php delete mode 100644 src/Services/Telephony/Result/ExternalLineDeleteResult.php delete mode 100644 src/Services/Telephony/Result/ExternalLineItemResult.php delete mode 100644 src/Services/Telephony/Result/ExternalLineUpdateResult.php delete mode 100644 src/Services/Telephony/Result/ExternalLinesResult.php delete mode 100644 tests/Integration/Services/Telephony/Service/CallTest.php delete mode 100644 tests/Integration/Services/Telephony/Service/ExternalCallTest.php delete mode 100644 tests/Integration/Services/Telephony/Service/ExternalLineTest.php delete mode 100644 tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php delete mode 100644 tests/Integration/Services/Telephony/Service/assets/test-phone-record.mp3 diff --git a/src/Services/Telephony/Common/CallType.php b/src/Services/Telephony/Common/CallType.php deleted file mode 100644 index acc7d8ab..00000000 --- a/src/Services/Telephony/Common/CallType.php +++ /dev/null @@ -1,123 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\SDK\Services\Telephony\Common; - -use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; - -class CallType -{ - private const OUTBOUND_CALL = 1; - private const INBOUND_CALL = 2; - private const INBOUND_CALL_WITH_REDIRECTION = 3; - private const CALLBACK = 4; - private int $code; - - /** - * @param int $typeCode - * - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException - */ - - private function __construct(int $typeCode) - { - switch ($typeCode) { - case $this::INBOUND_CALL: - case $this::OUTBOUND_CALL: - case $this::INBOUND_CALL_WITH_REDIRECTION: - case $this::CALLBACK: - $this->code = $typeCode; - break; - default: - throw new InvalidArgumentException(sprintf('unknown type call %s', $typeCode)); - } - } - - /** - * @return self - */ - public static function outboundCall(): self - { - return new self(self::OUTBOUND_CALL); - } - - /** - * @return bool - */ - public function isOutboundCall(): bool - { - return $this->code === self::OUTBOUND_CALL; - } - - /** - * @return self - */ - public static function inboundCall(): self - { - return new self(self::INBOUND_CALL); - } - - /** - * @return bool - */ - public function isInboundCall(): bool - { - return $this->code === self::INBOUND_CALL; - } - - /** - * @return self - */ - public static function inboundCallWithRedirection(): self - { - return new self(self::INBOUND_CALL_WITH_REDIRECTION); - } - - /** - * @return bool - */ - public function isInboundCallWithRedirection(): bool - { - return $this->code === self::INBOUND_CALL_WITH_REDIRECTION; - } - - /** - * @return self - */ - public static function callback(): self - { - return new self(self::CALLBACK); - } - - /** - * @return bool - */ - public function isCallback(): bool - { - return $this->code === self::CALLBACK; - } - - public function __toString(): string - { - return (string)$this->code; - } - - /** - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException - */ - public static function initByTypeCode(int $callTypeCode): self - { - return new self($callTypeCode); - } -} - diff --git a/src/Services/Telephony/Common/CrmEntityType.php b/src/Services/Telephony/Common/CrmEntityType.php deleted file mode 100644 index 99d280a4..00000000 --- a/src/Services/Telephony/Common/CrmEntityType.php +++ /dev/null @@ -1,106 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\SDK\Services\Telephony\Common; - -use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; - -class CrmEntityType -{ - private const CONTACT = 'CONTACT'; - private const COMPANY = 'COMPANY'; - private const LEAD = 'LEAD'; - private string $code; - - /** - * @param string $typeCode - * - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException - */ - private function __construct(string $typeCode) - { - switch ($typeCode) { - case $this::COMPANY: - case $this::CONTACT: - case $this::LEAD: - $this->code = $typeCode; - break; - default: - throw new InvalidArgumentException(sprintf('unknown crm entity type code %s', $typeCode)); - } - } - - /** - * @return self - */ - public static function contact(): self - { - return new self(self::CONTACT); - } - - /** - * @return bool - */ - public function isContact(): bool - { - return $this->code === $this::CONTACT; - } - - /** - * @return self - */ - public static function company(): self - { - return new self(self::COMPANY); - } - - /** - * @return bool - */ - public function isCompany(): bool - { - return $this->code === $this::COMPANY; - } - - /** - * @return self - */ - public static function lead(): self - { - return new self(self::LEAD); - } - - /** - * @return bool - */ - public function isLead(): bool - { - return $this->code === $this::LEAD; - } - - /** - * @return string - */ - public function __toString(): string - { - return $this->code; - } - - /** - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException - */ - public static function initByCode(string $entityTypeCode): self - { - return new self($entityTypeCode); - } -} \ No newline at end of file diff --git a/src/Services/Telephony/Common/StatusSipCodeInterface.php b/src/Services/Telephony/Common/StatusSipCodeInterface.php deleted file mode 100644 index f3e9a0c7..00000000 --- a/src/Services/Telephony/Common/StatusSipCodeInterface.php +++ /dev/null @@ -1,100 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\SDK\Services\Telephony\Common; - -interface StatusSipCodeInterface -{ - //Provisional Responses - public const STATUS_RINGING = 180; - public const STATUS_CALL_IS_BEING_FORWARDED = 181; - public const STATUS_QUEUED = 182; - public const STATUS_SESSION_PROGRESS = 183; - public const STATUS_EARLY_DIALOG_TERMINATED = 199; - //Successful Responses - public const STATUS_OK = 200; - public const STATUS_ACCEPTED = 202; - public const STATUS_NO_NOTIFICATION = 204; - //Redirection Responses - public const STATUS_MULTIPIE_CHOICES = 300; - public const STATUS_MOVED_PERMANENTLY = 301; - public const STATUS_MOVED_TEMPORARILY = 302; - public const STATUS_USE_PROXY = 305; - public const STATUS_ALTERNATIVE_SERVICE = 380; - //Client Failure Responses - public const STATUS_BAD_REQUEST = 400; - public const STATUS_UNAUTHORIZED = 401; - public const STATUS_PAYMENT_REQUIRED = 402; - public const STATUS_FORBIDDEN = 403; - public const STATUS_NOT_FOUND = 404; - public const STATUS_METHOD_NOT_ALLOWED = 405; - public const STATUS_NOT_ACCEPTABLE = 406; - public const STATUS_PROXY_AUTHENTICATION_REQUIRED = 407; - public const STATUS_REQUEST_TIMEOUT = 408; - public const STATUS_C0NFLICT = 409; - public const STATUS_GONE = 410; - public const STATUS_LENGTH_REQUIRED = 411; - public const STATUS_CONDITIONAL_REQUEST_FAILED = 412; - public const STATUS_REQUEST_ENTITY_TOO_LARGE = 413; - public const STATUS_REQUEST_URI_TOO_LONG = 414; - public const STATUS_UNSUPPORTED_MEDIA_TYPE = 415; - public const STATUS_UNSUPPORTED_URI_SCHEME = 416; - public const STATUS_UNKNOWN_RESOURCE_PRIORITY = 417; - public const STATUS_BAD_EXTENSION = 420; - public const STATUS_EXTENSION_REQUIRED = 421; - public const STATUS_SESSION_INTERVAL_TOO_SMALL = 422; - public const STATUS_INTERVAL_TOO_BRIED = 423; - public const STATUS_BAD_LOCATION_INFORMATION = 424; - public const STATUS_BAD_ALERT_MESSAGE = 425; - public const STATUS_USE_IDENTITY_HEADER = 428; - public const STATUS_PROVIDE_REFERRER_IDENTITY = 429; - public const STATUS_FLOW_FAILED = 430; - public const STATUS_ANONYMITY_DISALLOWED = 433; - public const STATUS_BAD_IDENTITY_INFO = 436; - public const STATUS_UNSUPPORTED_CERTIFICATE = 437; - public const STATUS_INVALID_IDENTITY_HEADER = 438; - public const STATUS_FIRST_HOP_LACKS_OUTBOUND_SUPPORT = 439; - public const STATUS_MAX_BREADTH_EXCEEDED = 440; - public const STATUS_BAD_INFO_PACKAGE = 469; - public const STATUS_CONSENT_NEEDED = 470; - public const STATUS_TEMPORARILY_UNAVAILABLE = 480; - public const STATUS_CALL_OR_TRANSACTION_DOES_NOT_EXIST = 481; - public const STATUS_LOOP_DETECTED = 482; - public const STATUS_TOO_MANY_HOPS = 483; - public const STATUS_ADDRESS_INCOMPLETE = 484; - public const STATUS_AMBIGUOUS = 485; - public const STATUS_BUSY_HERE = 486; - public const STATUS_REQUEST_TERMINATED = 487; - public const STATUS_NOT_ACCEPTABLE_HERE = 488; - public const STATUS_BAD_EVENT = 489; - public const STATUS_REQUEST_PENDING = 491; - public const STATUS_UNDECIPHERABLE = 493; - public const STATUS_SECURITY_AGREEMENT_REQUIRED = 494; - //Server Failure Responses - public const STATUS_INTERNAL_SERVER_ERROR = 500; - public const STATUS_NOT_IMPLEMENTED = 501; - public const STATUS_BAD_GATEWAY = 502; - public const STATUS_SERVICE_UNAVAILABLE = 503; - public const STATUS_SERVER_TIME_OUT = 504; - public const STATUS_VERSION_NOT_SUPPORTED = 505; - public const STATUS_MESSAGE_TOO_LARGE = 513; - public const STATUS_PUSH_NOTIFICATION_SERVICE_NOT_SUPPORTED = 555; - public const STATUS_PRECONDITION_FAILURE = 580; - //Global Failure Responses - public const STATUS_BUSY_EVERYWHERE = 600; - public const STATUS_DECLINE = 603; - public const STATUS_DOES_NOT_EXIST_ANYWHERE = 604; - public const STATUS_GLOBAL_NOT_ACCEPTABLE = 606; - public const STATUS_UNWANTED = 607; - public const STATUS_REJECTED = 608; -} \ No newline at end of file diff --git a/src/Services/Telephony/Common/StatusSipRegistrations.php b/src/Services/Telephony/Common/StatusSipRegistrations.php deleted file mode 100644 index 6c2984c2..00000000 --- a/src/Services/Telephony/Common/StatusSipRegistrations.php +++ /dev/null @@ -1,83 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\SDK\Services\Telephony\Common; - -use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; - -class StatusSipRegistrations -{ - private const SUCCESS = 'success'; - private const ERROR = 'error'; - private const IN_PROGRESS = 'in_progress'; - private const WAIT = 'wait'; - private string $code; - - /** - * @param string $typeSip - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException - */ - private function __construct(string $typeSip) - { - switch ($typeSip) { - case $this::SUCCESS: - case $this::ERROR: - case $this::IN_PROGRESS: - case $this::WAIT: - $this->code = $typeSip; - break; - default: - throw new InvalidArgumentException(sprintf('unknown status SIP registrations %s', $typeSip)); - } - } - - /** - * @return self - */ - public static function success(): self - { - return new self(self::SUCCESS); - } - - /** - * @return self - */ - public static function error(): self - { - return new self(self::ERROR); - } - - /** - * @return self - */ - public static function in_progress(): self - { - return new self(self::IN_PROGRESS); - } - - /** - * @return self - */ - public static function wait(): self - { - return new self(self::WAIT); - } - - /** - * @return string - */ - public function __toString(): string - { - return $this->code; - } -} \ No newline at end of file diff --git a/src/Services/Telephony/Common/TypeAtc.php b/src/Services/Telephony/Common/TypeAtc.php deleted file mode 100644 index af0ad7bb..00000000 --- a/src/Services/Telephony/Common/TypeAtc.php +++ /dev/null @@ -1,63 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\SDK\Services\Telephony\Common; - -use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; - -class TypeAtc -{ - private const CLOUD = 'cloud'; - private const OFFICE = 'office'; - private string $code; - - /** - * @param string $typeAtc - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException - */ - private function __construct(string $typeAtc) - { - switch ($typeAtc) { - case $this::CLOUD: - case $this::OFFICE: - $this->code = $typeAtc; - break; - default: - throw new InvalidArgumentException(sprintf('unknown type ATC %s', $typeAtc)); - } - } - - /** - * @return self - */ - public static function cloud(): self - { - return new self(self::CLOUD); - } - - /** - * @return self - */ - public static function office(): self - { - return new self(self::OFFICE); - } - - /** - * @return string - */ - public function __toString(): string - { - return $this->code; - } -} \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/Auth.php b/src/Services/Telephony/Requests/Events/Auth.php deleted file mode 100644 index a0a3dadd..00000000 --- a/src/Services/Telephony/Requests/Events/Auth.php +++ /dev/null @@ -1,41 +0,0 @@ - Scope::initFromString((string)$this->data[$offset]), - 'status' => ApplicationStatus::initFromString((string)$this->data[$offset]), - 'user_id', 'expires_in', 'expires' => (int)$this->data[$offset], - default => parent::__get($offset), - }; - } -} \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/OnExternalCallBackStart.php b/src/Services/Telephony/Requests/Events/OnExternalCallBackStart.php deleted file mode 100644 index 7582e152..00000000 --- a/src/Services/Telephony/Requests/Events/OnExternalCallBackStart.php +++ /dev/null @@ -1,60 +0,0 @@ -eventPayload['data']['PHONE_NUMBER']; - } - - /** - * @return string Text to be voiced over to a user during initiated call (). - */ - public function getText(): string - { - return $this->eventPayload['data']['TEXT']; - } - - /** - * @return string Voice ID to be used for text voiceover (via form settings). To get a voice IDs list, see voximplant.tts.voices.get. - */ - public function getVoiceId(): string - { - return $this->eventPayload['data']['VOICE']; - } - - /** - * @return \Bitrix24\SDK\Services\Telephony\Common\CrmEntityType - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException - */ - public function getCrmEntityType(): CrmEntityType - { - return CrmEntityType::initByCode($this->eventPayload['data']['CRM_ENTITY_TYPE']); - } - - /** - * @return int CRM entity ID with type specified in CRM_ENTITY_TYPE. - */ - public function getCrmEntityId(): int - { - return (int)$this->eventPayload['data']['CRM_ENTITY_ID']; - } - - /** - * @return string Number of external line used to request a callback - */ - public function getLineNumber(): string - { - return $this->eventPayload['data']['LINE_NUMBER']; - } -} \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/OnExternalCallStart/CallData.php b/src/Services/Telephony/Requests/Events/OnExternalCallStart/CallData.php deleted file mode 100644 index 6a876d0d..00000000 --- a/src/Services/Telephony/Requests/Events/OnExternalCallStart/CallData.php +++ /dev/null @@ -1,42 +0,0 @@ - (int)$this->data[$offset] !== 0, - 'CALL_TYPE' => CallType::initByTypeCode((int)$this->data[$offset]), - 'CRM_ENTITY_TYPE' => (string)$this->data[$offset], - 'REST_APP_ID', 'CALL_LIST_ID', 'CRM_CREATED_LEAD', 'CRM_ENTITY_ID', 'USER_ID' => (int)$this->data[$offset], - default => parent::__get($offset), - }; - } -} \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/OnExternalCallStart/OnExternalCallStart.php b/src/Services/Telephony/Requests/Events/OnExternalCallStart/OnExternalCallStart.php deleted file mode 100644 index a15f1318..00000000 --- a/src/Services/Telephony/Requests/Events/OnExternalCallStart/OnExternalCallStart.php +++ /dev/null @@ -1,30 +0,0 @@ -eventPayload['data']); - } - - /** - * @return \Bitrix24\SDK\Services\Telephony\Requests\Events\Auth - */ - public function getAuth(): Auth - { - return new Auth($this->eventPayload['auth']); - } -} \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd/CallData.php b/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd/CallData.php deleted file mode 100644 index b8ddfbd0..00000000 --- a/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd/CallData.php +++ /dev/null @@ -1,68 +0,0 @@ -data[$offset]; - case 'CALL_START_DATE': - return new \DateTimeImmutable((string)$this->data[$offset]); - case 'CALL_TYPE': - return CallType::initByTypeCode((int)$this->data[$offset]); - case 'CALL_DURATION': - case 'CALL_FAILED_CODE': - case 'CRM_ACTIVITY_ID': - case 'PORTAL_USER_ID': - return (int)$this->data[$offset]; - case 'COST_CURRENCY': - return new Currency($this->data[$offset]); - case 'COST': - if ($this->data[$offset] === null) { - return new Money(0, new Currency($this->data['COST_CURRENCY'])); - } - - return (new DecimalMoneyParser(new ISOCurrencies()))->parse( - $this->data[$offset], - new Currency($this->data['COST_CURRENCY']) - ); - default: - return parent::__get($offset); - } - } -} \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd/OnVoximplantCallEnd.php b/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd/OnVoximplantCallEnd.php deleted file mode 100644 index 1b0697ad..00000000 --- a/src/Services/Telephony/Requests/Events/OnVoximplantCallEnd/OnVoximplantCallEnd.php +++ /dev/null @@ -1,35 +0,0 @@ -eventPayload['auth']); - } - - /** - * @return \Bitrix24\SDK\Services\Telephony\Requests\Events\OnVoximplantCallEnd\CallData - */ - public function getCallData(): CallData - { - return new CallData($this->eventPayload['data']); - } -} \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/OnVoximplantCallInit/CallData.php b/src/Services/Telephony/Requests/Events/OnVoximplantCallInit/CallData.php deleted file mode 100644 index 383db9bb..00000000 --- a/src/Services/Telephony/Requests/Events/OnVoximplantCallInit/CallData.php +++ /dev/null @@ -1,35 +0,0 @@ - CallType::initByTypeCode((int)$this->data[$offset]), - 'REST_APP_ID' => (int)$this->data[$offset], - default => parent::__get($offset), - }; - } -} \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/OnVoximplantCallInit/OnVoximplantCallInit.php b/src/Services/Telephony/Requests/Events/OnVoximplantCallInit/OnVoximplantCallInit.php deleted file mode 100644 index 2e0c2889..00000000 --- a/src/Services/Telephony/Requests/Events/OnVoximplantCallInit/OnVoximplantCallInit.php +++ /dev/null @@ -1,32 +0,0 @@ -eventPayload['auth']); - } - - /** - * @return \Bitrix24\SDK\Services\Telephony\Requests\Events\OnVoximplantCallInit\CallData - */ - public function getCallData(): CallData - { - return new CallData($this->eventPayload['data']); - } -} \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/OnVoximplantCallStart/CallData.php b/src/Services/Telephony/Requests/Events/OnVoximplantCallStart/CallData.php deleted file mode 100644 index 86a08f01..00000000 --- a/src/Services/Telephony/Requests/Events/OnVoximplantCallStart/CallData.php +++ /dev/null @@ -1,28 +0,0 @@ - (int)$this->data[$offset], - default => parent::__get($offset), - }; - } -} \ No newline at end of file diff --git a/src/Services/Telephony/Requests/Events/OnVoximplantCallStart/OnVoximplantCallStart.php b/src/Services/Telephony/Requests/Events/OnVoximplantCallStart/OnVoximplantCallStart.php deleted file mode 100644 index 6138ac4f..00000000 --- a/src/Services/Telephony/Requests/Events/OnVoximplantCallStart/OnVoximplantCallStart.php +++ /dev/null @@ -1,29 +0,0 @@ -eventPayload['auth']); - } - /** - * @return \Bitrix24\SDK\Services\Telephony\Requests\Events\OnVoximplantCallStart\CallData - */ - public function getCallData(): CallData - { - return new CallData($this->eventPayload['data']); - } -} \ No newline at end of file diff --git a/src/Services/Telephony/Result/CallAttachTranscriptionResult.php b/src/Services/Telephony/Result/CallAttachTranscriptionResult.php deleted file mode 100644 index d68269ca..00000000 --- a/src/Services/Telephony/Result/CallAttachTranscriptionResult.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\SDK\Services\Telephony\Result; - -use Bitrix24\SDK\Core\Contracts\AddedItemIdResultInterface; -use Bitrix24\SDK\Core\Exceptions\BaseException; -use Bitrix24\SDK\Core\Result\AbstractResult; - -class CallAttachTranscriptionResult extends AbstractResult implements AddedItemIdResultInterface -{ - /** - * @return int - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - */ - - public function getId():int - { - return $this->getCoreResponse()->getResponseData()->getResult()['TRANSCRIPT_ID']; - } -} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallFinishItemResult.php b/src/Services/Telephony/Result/ExternalCallFinishItemResult.php deleted file mode 100644 index 4057a89d..00000000 --- a/src/Services/Telephony/Result/ExternalCallFinishItemResult.php +++ /dev/null @@ -1,46 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\SDK\Services\Telephony\Result; - - -use Bitrix24\SDK\Core\Result\AbstractItem; - -/** - * @property-read string $CALL_ID - * @property-read int $EXTERNAL_CALL_ID - * @property-read int $PORTAL_USER_ID - * @property-read string $PHONE_NUMBER - * @property-read string $PORTAL_NUMBER - * @property-read string $INCOMING - * @property-read int $CALL_DURATION - * @property-read array $CALL_START_DATE - * @property-read int $CALL_STATUS - * @property-read int $CALL_VOTE - * @property-read int $COST - * @property-read string $COST_CURRENCY - * @property-read string $CALL_FAILED_CODE - * @property-read string $CALL_FAILED_REASON - * @property-read int $REST_APP_ID - * @property-read bool $REST_APP_NAME - * @property-read int $CRM_ACTIVITY_ID - * @property-read string $COMMENT - * @property-read string $CRM_ENTITY_TYPE - * @property-read int $CRM_ENTITY_ID - * @property-read int $ID - * - */ -class ExternalCallFinishItemResult extends AbstractItem -{ - -} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallFinishResult.php b/src/Services/Telephony/Result/ExternalCallFinishResult.php deleted file mode 100644 index f7622c71..00000000 --- a/src/Services/Telephony/Result/ExternalCallFinishResult.php +++ /dev/null @@ -1,29 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\SDK\Services\Telephony\Result; - -use Bitrix24\SDK\Core\Exceptions\BaseException; -use Bitrix24\SDK\Core\Result\AbstractResult; - -class ExternalCallFinishResult extends AbstractResult -{ - /** - * @return \Bitrix24\SDK\Services\Telephony\Result\ExternalCallFinishItemResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - */ - public function getExternalCallFinish(): ExternalCallFinishItemResult - { - return new ExternalCallFinishItemResult($this->getCoreResponse()->getResponseData()->getResult()); - } -} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallHideResult.php b/src/Services/Telephony/Result/ExternalCallHideResult.php deleted file mode 100644 index b1a0661f..00000000 --- a/src/Services/Telephony/Result/ExternalCallHideResult.php +++ /dev/null @@ -1,31 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\SDK\Services\Telephony\Result; - -use Bitrix24\SDK\Core\Exceptions\BaseException; -use Bitrix24\SDK\Core\Result\AbstractResult; - -class ExternalCallHideResult extends AbstractResult -{ - - /** - * @return bool - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - */ - - public function isHided(): bool - { - return $this->getCoreResponse()->getResponseData()->getResult()[0]; - } -} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallRecordResult.php b/src/Services/Telephony/Result/ExternalCallRecordResult.php deleted file mode 100644 index 7437a324..00000000 --- a/src/Services/Telephony/Result/ExternalCallRecordResult.php +++ /dev/null @@ -1,28 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\SDK\Services\Telephony\Result; - -use Bitrix24\SDK\Core\Exceptions\BaseException; -use Bitrix24\SDK\Core\Result\AbstractResult; - -class ExternalCallRecordResult extends AbstractResult -{ - /** - * @return int - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - */ - public function getFileId():int - { - return $this->getCoreResponse()->getResponseData()->getResult()['FILE_ID']; - } -} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallRegisterItemResult.php b/src/Services/Telephony/Result/ExternalCallRegisterItemResult.php deleted file mode 100644 index 9b4796d5..00000000 --- a/src/Services/Telephony/Result/ExternalCallRegisterItemResult.php +++ /dev/null @@ -1,40 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\SDK\Services\Telephony\Result; - -use Bitrix24\SDK\Core\Result\AbstractItem; - -/** - * If registration of the call was unsuccessful, the LEAD_CREATION_ERROR field will contain the error message. - * - * @property-read string $CALL_ID - * @property-read ?int $CRM_CREATED_LEAD - * @property-read ?int $CRM_ENTITY_ID - * @property-read string $CRM_ENTITY_TYPE - * @property-read array $CRM_CREATED_ENTITIES - * @property-read string $LEAD_CREATION_ERROR - */ -class ExternalCallRegisterItemResult extends AbstractItem -{ - /** - * @return bool - */ - 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/Result/ExternalCallRegisterResult.php b/src/Services/Telephony/Result/ExternalCallRegisterResult.php deleted file mode 100644 index 232cca7e..00000000 --- a/src/Services/Telephony/Result/ExternalCallRegisterResult.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\SDK\Services\Telephony\Result; - -use Bitrix24\SDK\Core\Exceptions\BaseException; -use Bitrix24\SDK\Core\Result\AbstractResult; - -class ExternalCallRegisterResult extends AbstractResult -{ - /** - * @return \Bitrix24\SDK\Services\Telephony\Result\ExternalCallRegisterItemResult - * @throws BaseException - */ - public function getExternalCallRegister(): ExternalCallRegisterItemResult - { - return new ExternalCallRegisterItemResult($this->getCoreResponse()->getResponseData()->getResult()); - } - -} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesItemResult.php b/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesItemResult.php deleted file mode 100644 index 891ef5c2..00000000 --- a/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesItemResult.php +++ /dev/null @@ -1,28 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\SDK\Services\Telephony\Result; - -use Bitrix24\SDK\Core\Result\AbstractItem; - -/** - * @property-read string $CRM_ENTITY_TYPE - * @property-read int $CRM_ENTITY_ID - * @property-read int $ASSIGNED_BY_ID - * @property-read string $NAME - * @property-read array $ASSIGNED_BY - */ - -class ExternalCallSearchCrmEntitiesItemResult extends AbstractItem -{ -} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php b/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php deleted file mode 100644 index 7d67626c..00000000 --- a/src/Services/Telephony/Result/ExternalCallSearchCrmEntitiesResult.php +++ /dev/null @@ -1,34 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\SDK\Services\Telephony\Result; - -use Bitrix24\SDK\Core\Result\AbstractResult; - -class ExternalCallSearchCrmEntitiesResult extends AbstractResult -{ - /** - * @return ExternalCallSearchCrmEntitiesItemResult[] - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - */ - - public function getCrmEntitiesSearchResult():array - { - $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { - $res[] = new ExternalCallSearchCrmEntitiesItemResult($item); - } - - return $res; - } -} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalCallShowResult.php b/src/Services/Telephony/Result/ExternalCallShowResult.php deleted file mode 100644 index d275e402..00000000 --- a/src/Services/Telephony/Result/ExternalCallShowResult.php +++ /dev/null @@ -1,34 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\SDK\Services\Telephony\Result; - -use Bitrix24\SDK\Core\Contracts\AddedItemIdResultInterface; -use Bitrix24\SDK\Core\Exceptions\BaseException; -use Bitrix24\SDK\Core\Result\AbstractResult; - -class ExternalCallShowResult extends AbstractResult -{ - - /** - * @return bool - * @throws BaseException - */ - - public function isShown(): bool - { - return $this->getCoreResponse()->getResponseData()->getResult()[0]; - } - - -} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalLineAddResult.php b/src/Services/Telephony/Result/ExternalLineAddResult.php deleted file mode 100644 index c287a5f9..00000000 --- a/src/Services/Telephony/Result/ExternalLineAddResult.php +++ /dev/null @@ -1,31 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\SDK\Services\Telephony\Result; - -use Bitrix24\SDK\Core\Contracts\AddedItemIdResultInterface; -use Bitrix24\SDK\Core\Exceptions\BaseException; -use Bitrix24\SDK\Core\Result\AbstractResult; - -class ExternalLineAddResult extends AbstractResult implements AddedItemIdResultInterface -{ - /** - * @return int - * @throws BaseException - */ - public function getId(): int - { - return $this->getCoreResponse()->getResponseData()->getResult()['ID']; - } - -} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalLineDeleteResult.php b/src/Services/Telephony/Result/ExternalLineDeleteResult.php deleted file mode 100644 index f8f0d570..00000000 --- a/src/Services/Telephony/Result/ExternalLineDeleteResult.php +++ /dev/null @@ -1,21 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\SDK\Services\Telephony\Result; - -use Bitrix24\SDK\Core\Exceptions\BaseException; -use Bitrix24\SDK\Core\Result\AbstractResult; - -class ExternalLineDeleteResult extends AbstractResult -{ -} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalLineItemResult.php b/src/Services/Telephony/Result/ExternalLineItemResult.php deleted file mode 100644 index 426039d6..00000000 --- a/src/Services/Telephony/Result/ExternalLineItemResult.php +++ /dev/null @@ -1,26 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\SDK\Services\Telephony\Result; - -use Bitrix24\SDK\Core\Result\AbstractItem; - -/** - * @property-read string $NUMBER - * @property-read string $NAME - */ - -class ExternalLineItemResult extends AbstractItem -{ - -} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalLineUpdateResult.php b/src/Services/Telephony/Result/ExternalLineUpdateResult.php deleted file mode 100644 index 3e08575d..00000000 --- a/src/Services/Telephony/Result/ExternalLineUpdateResult.php +++ /dev/null @@ -1,29 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\SDK\Services\Telephony\Result; - -use Bitrix24\SDK\Core\Exceptions\BaseException; -use Bitrix24\SDK\Core\Result\AbstractResult; - -class ExternalLineUpdateResult extends AbstractResult -{ - /** - * @return int - * @throws BaseException - */ - public function updateExternalLineId():int - { - return (int)$this->getCoreResponse()->getResponseData()->getResult()['ID']; - } -} \ No newline at end of file diff --git a/src/Services/Telephony/Result/ExternalLinesResult.php b/src/Services/Telephony/Result/ExternalLinesResult.php deleted file mode 100644 index 9345c9eb..00000000 --- a/src/Services/Telephony/Result/ExternalLinesResult.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\SDK\Services\Telephony\Result; - -use Bitrix24\SDK\Core\Exceptions\BaseException; -use Bitrix24\SDK\Core\Result\AbstractResult; - -class ExternalLinesResult extends AbstractResult -{ - /** - * @return ExternalLineItemResult[] - * @throws BaseException - */ - public function getExternalLines(): array - { - $res = []; - foreach ($this->getCoreResponse()->getResponseData()->getResult() as $item) { - $res[] = new ExternalLineItemResult($item); - } - - return $res; - } -} \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/Service/CallTest.php b/tests/Integration/Services/Telephony/Service/CallTest.php deleted file mode 100644 index a3d5e266..00000000 --- a/tests/Integration/Services/Telephony/Service/CallTest.php +++ /dev/null @@ -1,139 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\SDK\Tests\Integration\Services\Telephony\Service; - -use Bitrix24\SDK\Core\Exceptions\BaseException; -use Bitrix24\SDK\Core\Exceptions\TransportException; -use Bitrix24\SDK\Services\CRM\Contact\Service\Contact; -use Bitrix24\SDK\Services\CRM\Lead\Service\Lead; -use Bitrix24\SDK\Services\Main\Service\Main; -use Bitrix24\SDK\Services\Telephony\Common\CallType; -use Bitrix24\SDK\Services\Telephony\Common\CrmEntityType; -use Bitrix24\SDK\Services\Telephony\Common\StatusSipCodeInterface; -use Bitrix24\SDK\Services\Telephony\Service\Call; -use Bitrix24\SDK\Services\Telephony\Service\ExternalCall; -use Bitrix24\SDK\Tests\Integration\Fabric; -use DateTime; -use DateTimeInterface; -use Exception; -use Money\Currencies\ISOCurrencies; -use Money\Currency; -use Money\Formatter\DecimalMoneyFormatter; -use Money\Formatter\IntlMoneyFormatter; -use Money\Money; -use PHPUnit\Framework\TestCase; - -class CallTest extends TestCase -{ - protected Call $callService; - protected Lead $leadService; - protected ExternalCall $externalCallService; - protected Main $mainService; - protected Contact $contactService; - - - /** - * @throws BaseException - * @throws TransportException - * @throws Exception - * @covers Call::attachTranscription - */ - public function testAttachTranscription(): void - { - $datetime = new DateTime('now'); - $callStartDate = $datetime->format(DateTimeInterface::ATOM); - $phoneNumber = sprintf('+7%s', time()); - $callCosts = new Money(1000, new Currency('RUB')); - $currencies = new ISOCurrencies(); - - $moneyFormatter = new DecimalMoneyFormatter($currencies); - - - $contactId = $this->contactService->add( - [ - 'NAME' => 'Глеб', - 'SECOND_NAME' => 'Егорович', - 'PHONE' => [ - [ - 'VALUE' => $phoneNumber, - 'VALUE_TYPE' => 'WORK' - ] - ] - ] - )->getId(); - - $userId = $this->mainService->getCurrentUserProfile()->getUserProfile()->ID; - - $messages = [ - [ - 'SIDE' => 'User', - 'START_TIME' => 1, - 'STOP_TIME' => 3, - 'MESSAGE' => 'HELLO WORLD' - ], - [ - 'SIDE' => "Client", - 'START_TIME' => 4, - 'STOP_TIME' => 8, - 'MESSAGE' => "Здравствуйте, вы продаете пылесосы?" - ], - ]; - - $registerCallResult = $this->externalCallService->registerCall([ - 'USER_PHONE_INNER' => '14', - 'USER_ID' => $userId, - 'PHONE_NUMBER' => $phoneNumber, - 'CALL_START_DATE' => $callStartDate, - 'CRM_CREATE' => 0, - 'CRM_SOURCE' => '1', - 'CRM_ENTITY_TYPE' => (string)CrmEntityType::contact(), - 'CRM_ENTITY_ID' => $contactId, - 'SHOW' => 1, - 'CALL_LIST_ID' => 1, - 'LINE_NUMBER' => $phoneNumber, - 'TYPE' => (string)CallType::outboundCall(), - ])->getExternalCallRegister(); - $finishCallResult = $this->externalCallService->finish([ - 'CALL_ID' => $registerCallResult->CALL_ID, - 'USER_ID' => $userId, - 'DURATION' => 255, - 'COST' => $moneyFormatter->format($callCosts), - 'COST_CURRENCY' => $callCosts->getCurrency()->getCode(), - 'STATUS_CODE' => StatusSipCodeInterface::STATUS_OK, - 'FAILED_REASON' => '', - 'RECORD_URL' => '', - 'VOTE' => 5, - 'ADD_TO_CHAT' => 1 - ])->getExternalCallFinish(); - - self::assertGreaterThanOrEqual(1, - $this->callService->attachTranscription( - $registerCallResult->CALL_ID, - $callCosts, - $messages)->getId() - ); - } - - /** - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException - */ - public function setUp(): void - { - $this->callService = Fabric::getServiceBuilder()->getTelephonyScope()->call(); - $this->externalCallService = Fabric::getServiceBuilder()->getTelephonyScope()->externalCall(); - $this->leadService = Fabric::getServiceBuilder()->getCRMScope()->lead(); - $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); - $this->mainService = Fabric::getServiceBuilder()->getMainScope()->main(); - } - -} \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php b/tests/Integration/Services/Telephony/Service/ExternalCallTest.php deleted file mode 100644 index efe6436f..00000000 --- a/tests/Integration/Services/Telephony/Service/ExternalCallTest.php +++ /dev/null @@ -1,308 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\SDK\Tests\Integration\Services\Telephony\Service; - - -use Bitrix24\SDK\Core\Exceptions\BaseException; -use Bitrix24\SDK\Core\Exceptions\TransportException; -use Bitrix24\SDK\Services\CRM\Contact\Service\Contact; -use Bitrix24\SDK\Services\CRM\Lead\Service\Lead; -use Bitrix24\SDK\Services\Main\Service\Main; -use Bitrix24\SDK\Services\Telephony\Common\CallType; -use Bitrix24\SDK\Services\Telephony\Common\CrmEntityType; -use Bitrix24\SDK\Services\Telephony\Common\StatusSipCodeInterface; -use Bitrix24\SDK\Services\Telephony\Service\ExternalCall; -use Bitrix24\SDK\Tests\Integration\Fabric; -use DateTime; -use DateTimeInterface; -use Exception; -use PHPUnit\Framework\TestCase; - -class ExternalCallTest extends TestCase -{ - protected Lead $leadService; - protected ExternalCall $externalCallService; - private Main $mainService; - protected Contact $contactService; - - /** - * @throws BaseException - * @throws TransportException - * @throws Exception - * @covers ExternalCall::registerCall - */ - - public function testRegisterCall(): void - { - $datetime = new DateTime('now'); - $callStartDate = $datetime->format(DateTimeInterface::ATOM); - $phoneNumber = sprintf('+7%s', time()); - $leadId = $this->leadService->add( - [ - 'TITLE' => 'test lead', - 'PHONE' => [ - [ - 'VALUE' => $phoneNumber, - 'VALUE_TYPE' => 'WORK' - ] - ] - ] - )->getId(); - $userId = $this->mainService->getCurrentUserProfile()->getUserProfile()->ID; - $registerCallResult = $this->externalCallService->registerCall([ - 'USER_PHONE_INNER' => '14', - 'USER_ID' => $userId, - 'PHONE_NUMBER' => $phoneNumber, - 'CALL_START_DATE' => $callStartDate, - 'CRM_CREATE' => 0, - 'CRM_SOURCE' => '1', - 'CRM_ENTITY_TYPE' => (string)CrmEntityType::lead(), - 'CRM_ENTITY_ID' => $leadId, - 'SHOW' => 1, - 'CALL_LIST_ID' => 1, - 'LINE_NUMBER' => $phoneNumber, - 'TYPE' => (string)CallType::inboundCall(), - ])->getExternalCallRegister(); - - self::assertTrue((bool)$registerCallResult); - self::assertEquals($registerCallResult->CRM_ENTITY_ID, $leadId, sprintf('registered entity id : %s , and lead id: %s, should not differ', - $registerCallResult->CRM_ENTITY_ID, $leadId)); - } - - /** - * @throws BaseException - * @throws TransportException - * @throws Exception - * @covers ExternalCall::show - */ - - - public function testShowCallCard(): void - { - $datetime = new DateTime('now'); - $callStartDate = $datetime->format(DateTimeInterface::ATOM); - $phoneNumber = '+79788045001'; - $leadId = $this->leadService->add( - [ - 'TITLE' => 'test lead', - 'PHONE' => [ - [ - 'VALUE' => $phoneNumber, - 'VALUE_TYPE' => 'WORK' - ] - ] - ] - )->getId(); - $userId = $this->mainService->getCurrentUserProfile()->getUserProfile()->ID; - $registerCallResult = $this->externalCallService->registerCall([ - 'USER_PHONE_INNER' => '14', - 'USER_ID' => $userId, - 'PHONE_NUMBER' => $phoneNumber, - 'CALL_START_DATE' => $callStartDate, - 'CRM_CREATE' => 0, - 'CRM_SOURCE' => '1', - 'CRM_ENTITY_TYPE' => (string)CrmEntityType::lead(), - 'CRM_ENTITY_ID' => $leadId, - 'SHOW' => 0, - 'CALL_LIST_ID' => 1, - 'LINE_NUMBER' => $phoneNumber, - 'TYPE' => (string)CallType::inboundCall(), - ])->getExternalCallRegister(); - self::assertTrue($this->externalCallService->show($registerCallResult->CALL_ID, $userId)->isShown()); - } - - /** - * @throws BaseException - * @throws TransportException - * @throws Exception - * @covers ExternalCall::hide - */ - public function testHideCallCard(): void - { - $datetime = new DateTime('now'); - $callStartDate = $datetime->format(DateTimeInterface::ATOM); - $phoneNumber = '+79788045001'; - $leadId = $this->leadService->add( - [ - 'TITLE' => 'test lead', - 'PHONE' => [ - [ - 'VALUE' => $phoneNumber, - 'VALUE_TYPE' => 'WORK' - ] - ] - ] - )->getId(); - $userId = $this->mainService->getCurrentUserProfile()->getUserProfile()->ID; - $registerCallResult = $this->externalCallService->registerCall([ - 'USER_PHONE_INNER' => '14', - 'USER_ID' => $userId, - 'PHONE_NUMBER' => $phoneNumber, - 'CALL_START_DATE' => $callStartDate, - 'CRM_CREATE' => 0, - 'CRM_SOURCE' => '1', - 'CRM_ENTITY_TYPE' => (string)CrmEntityType::lead(), - 'CRM_ENTITY_ID' => $leadId, - 'SHOW' => 0, - 'CALL_LIST_ID' => 1, - 'LINE_NUMBER' => $phoneNumber, - 'TYPE' => (string)CallType::inboundCall(), - ])->getExternalCallRegister(); - self::assertTrue($this->externalCallService->hide($registerCallResult->CALL_ID, $userId)->isHided()); - } - - /** - * @throws TransportException - * @throws BaseException - * @throws Exception - * @covers ExternalCall::finish - */ - public function testFinish(): void - { - $datetime = new DateTime('now'); - $callStartDate = $datetime->format(DateTimeInterface::ATOM); - $phoneNumber = sprintf('+7%s', time()); - $leadId = $this->leadService->add( - [ - 'TITLE' => 'test lead', - 'PHONE' => [ - [ - 'VALUE' => $phoneNumber, - 'VALUE_TYPE' => 'WORK' - ] - ] - ] - )->getId(); - $userId = $this->mainService->getCurrentUserProfile()->getUserProfile()->ID; - $registerCallResult = $this->externalCallService->registerCall([ - 'USER_PHONE_INNER' => '14', - 'USER_ID' => $userId, - 'PHONE_NUMBER' => $phoneNumber, - 'CALL_START_DATE' => $callStartDate, - 'CRM_CREATE' => 0, - 'CRM_SOURCE' => '1', - 'CRM_ENTITY_TYPE' => (string)CrmEntityType::lead(), - 'CRM_ENTITY_ID' => $leadId, - 'SHOW' => 1, - 'CALL_LIST_ID' => 1, - 'LINE_NUMBER' => $phoneNumber, - 'TYPE' => (string)CallType::inboundCall(), - ])->getExternalCallRegister(); - - $finishCallResult = $this->externalCallService->finish([ - 'CALL_ID' => $registerCallResult->CALL_ID, - 'USER_ID' => $userId, - 'DURATION' => 255, - 'COST' => 250, - 'COST_CURRENCY' => 'RUB', - 'STATUS_CODE' => StatusSipCodeInterface::STATUS_OK, - 'FAILED_REASON' => '', - 'RECORD_URL' => '', - 'VOTE' => 5, - 'ADD_TO_CHAT' => 1 - ])->getExternalCallFinish(); - - self::assertEquals($registerCallResult->CALL_ID, $finishCallResult->CALL_ID, sprintf('registered: %s , and finish: %s, CALL_ID do not match', - $registerCallResult->CALL_ID, $finishCallResult->CALL_ID)); - - self::assertEquals($registerCallResult->CRM_ENTITY_ID, $finishCallResult->CRM_ENTITY_ID, sprintf('registered: %s , and finish: %s, ENTITY_ID do not match', - $registerCallResult->CRM_ENTITY_ID, $finishCallResult->CRM_ENTITY_ID)); - - self::assertNotEmpty($finishCallResult->CALL_DURATION, 'call time cannot be empty'); - self::assertNotEmpty($finishCallResult->COST, 'call cost cannot be empty'); - self::assertNotEmpty($finishCallResult->CALL_STATUS, 'status code must return call code and cannot be empty'); - self::assertNotEmpty($finishCallResult->PHONE_NUMBER, 'phone number cannot be empty'); - } - - /** - * @throws TransportException - * @throws BaseException - * @throws Exception - * @covers ExternalCall::attachRecord - */ - public function testAttachRecord(): void - { - $datetime = new DateTime('now'); - $callStartDate = $datetime->format(DateTimeInterface::ATOM); - $phoneNumber = sprintf('+7%s', time()); - $leadId = $this->leadService->add( - [ - 'TITLE' => 'test lead', - 'PHONE' => [ - [ - 'VALUE' => $phoneNumber, - 'VALUE_TYPE' => 'WORK' - ] - ] - ] - )->getId(); - $userId = $this->mainService->getCurrentUserProfile()->getUserProfile()->ID; - $registerCallResult = $this->externalCallService->registerCall([ - 'USER_PHONE_INNER' => '14', - 'USER_ID' => $userId, - 'PHONE_NUMBER' => $phoneNumber, - 'CALL_START_DATE' => $callStartDate, - 'CRM_CREATE' => 0, - 'CRM_SOURCE' => '1', - 'CRM_ENTITY_TYPE' => (string)CrmEntityType::lead(), - 'CRM_ENTITY_ID' => $leadId, - 'SHOW' => 1, - 'CALL_LIST_ID' => 1, - 'LINE_NUMBER' => $phoneNumber, - 'TYPE' => (string)CallType::inboundCall(), - ])->getExternalCallRegister(); - - $finishCallResult = $this->externalCallService->finish([ - 'CALL_ID' => $registerCallResult->CALL_ID, - 'USER_ID' => $userId, - 'DURATION' => 10, - 'COST' => 250, - 'COST_CURRENCY' => 'RUB', - 'STATUS_CODE' => StatusSipCodeInterface::STATUS_OK, - 'FAILED_REASON' => '', - 'RECORD_URL' => '', - 'VOTE' => 5, - 'ADD_TO_CHAT' => 1 - ])->getExternalCallFinish(); - - $fileName = sprintf('test%s.mp3', time()); - self::assertGreaterThan(1, $this->externalCallService->attachRecord($registerCallResult->CALL_ID, $fileName, $this->getFileInBase64())->getFileId()); - } - - /** - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException - */ - public function setUp(): void - { - $this->externalCallService = Fabric::getServiceBuilder()->getTelephonyScope()->externalCall(); - $this->leadService = Fabric::getServiceBuilder()->getCRMScope()->lead(); - $this->mainService = Fabric::getServiceBuilder()->getMainScope()->main(); - } - - - private function getFileInBase64(): string - { - $filePath = __DIR__ . '/assets/'; - $fileName = 'test-phone-record.mp3'; - $resBase64 = ''; - $handle = fopen($filePath . $fileName, "rb"); - if ($handle) { - $buffer = fread($handle, filesize($filePath . $fileName)); - $resBase64 = base64_encode($buffer); - } - fclose($handle); - - return $resBase64; - } -} \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/Service/ExternalLineTest.php b/tests/Integration/Services/Telephony/Service/ExternalLineTest.php deleted file mode 100644 index d8320432..00000000 --- a/tests/Integration/Services/Telephony/Service/ExternalLineTest.php +++ /dev/null @@ -1,110 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\SDK\Tests\Integration\Services\Telephony\Service; - -use Bitrix24\SDK\Core\Exceptions\BaseException; -use Bitrix24\SDK\Core\Exceptions\TransportException; -use Bitrix24\SDK\Services\Telephony\Service\ExternalLine; -use Bitrix24\SDK\Tests\Integration\Fabric; -use PHPUnit\Framework\TestCase; - -class ExternalLineTest extends TestCase -{ - protected ExternalLine $externalLineService; - - /** - * @throws BaseException - * @throws TransportException - * @covers ExternalLine::add - */ - public function testAdd(): void - { - self::assertGreaterThan(1, $this->externalLineService->add((string)time(), sprintf('phpUnit-%s', time()))->getId()); - } - - /** - * @throws BaseException - * @throws TransportException - * @covers ExternalLine::get - */ - public function testGet(): void - { - $this->externalLineService->add((string)time(), sprintf('phpUnit-%s', time())); - $this->externalLineService->add((string)time(), sprintf('phpUnit-%s', time())); - self::assertGreaterThanOrEqual(2, $this->externalLineService->get()->getExternalLines()); - } - - /** - * @throws BaseException - * @throws TransportException - * @throws \Exception - * @covers ExternalLine::update - */ - public function testUpdateExternalLineName(): void - { - $lineNumber = $this->getRandomLineNumber(); - $lineNameBefore = sprintf('phpUnit-%s-name-before', time()); - - $externalLineId = $this->externalLineService->add($lineNumber, $lineNameBefore)->getId(); - - - $lineNameAfter = sprintf('phpUnit-%s-name-after', time()); - $updatedLineId = $this->externalLineService->update($lineNumber, $lineNameAfter)->updateExternalLineId(); - $this->assertEquals($externalLineId, $updatedLineId, sprintf('external line id %s not equals with %s', - $externalLineId, - $updatedLineId - )); - - $externalLineNameAfter = array_column($this->externalLineService->get()->getExternalLines(), 'NAME'); - self::assertFalse(in_array($lineNameBefore, $externalLineNameAfter), - sprintf('expected update line name «%s» line name see %s name', $lineNameBefore, $lineNameAfter)); - } - - /** - * @throws BaseException - * @throws TransportException - * @throws \Exception - * @covers ExternalLine::delete - */ - public function testDelete(): void - { - $lineNumber = $this->getRandomLineNumber(); - - self::assertGreaterThan(1, $this->externalLineService->add($lineNumber, sprintf('phpUnit-%s', time()))->getId()); - $externalLineNumbersBefore = array_column($this->externalLineService->get()->getExternalLines(), 'NUMBER'); - - $this->externalLineService->delete($lineNumber); - $externalLineNumbersAfter = array_column($this->externalLineService->get()->getExternalLines(), 'NUMBER'); - - $deletedLineNumber = array_values(array_diff($externalLineNumbersBefore, $externalLineNumbersAfter))[0]; - self::assertEquals($lineNumber, $deletedLineNumber, sprintf('expected deleted %s number see %s number', $lineNumber, $deletedLineNumber)); - } - - /** - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException - */ - public function setUp(): void - { - $this->externalLineService = Fabric::getServiceBuilder()->getTelephonyScope()->externalline(); - } - - /** - * @return string - * @throws \Exception - */ - private function getRandomLineNumber(): string - { - return (string)time() . (string)random_int(1, PHP_INT_MAX); - } -} \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php b/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php deleted file mode 100644 index 91365b68..00000000 --- a/tests/Integration/Services/Telephony/Service/SearchCrmEntitiesTest.php +++ /dev/null @@ -1,201 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\SDK\Tests\Integration\Services\Telephony\Service; - -use Bitrix24\SDK\Core\Exceptions\BaseException; -use Bitrix24\SDK\Core\Exceptions\TransportException; -use Bitrix24\SDK\Services\CRM\Contact\Service\Contact; -use Bitrix24\SDK\Services\CRM\Lead\Service\Lead; -use Bitrix24\SDK\Services\Telephony\Service\ExternalCall; -use Bitrix24\SDK\Tests\Integration\Fabric; -use Exception; -use PHPUnit\Framework\TestCase; - -class SearchCrmEntitiesTest extends TestCase -{ - - protected Lead $leadService; - protected ExternalCall $externalCallService; - protected Contact $contactService; - - /** - * @throws Exception - * @covers ExternalCall::searchCrmEntities - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - */ - public function testSearchCrmEntitiesWithEmptyResult(): void - { - //Не зарегистрированный телефон - $unusedPhone = '+51045005010'; - $infoAboutNotExistingCustomerResult = $this->externalCallService->searchCrmEntities($unusedPhone)->getCrmEntitiesSearchResult(); - self::assertEmpty($infoAboutNotExistingCustomerResult, sprintf('No customers can be found for this number: %s', $unusedPhone)); - } - - /** - * @throws Exception - * @covers ExternalCall::searchCrmEntities - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - */ - public function testSearchCrmEntitiesContactFound(): void - { - //Зарегистрированный контакт - $phoneNumberClient = sprintf('+7%s%s', time(), random_int(1, PHP_INT_MAX)); - $contactId = $this->contactService->add( - [ - 'NAME' => 'Глеб', - 'SECOND_NAME' => 'Егорович', - 'PHONE' => [ - [ - 'VALUE' => $phoneNumberClient, - 'VALUE_TYPE' => 'WORK', - ], - ], - ] - )->getId(); - $infoAboutClientResult = $this->externalCallService->searchCrmEntities($phoneNumberClient)->getCrmEntitiesSearchResult(); - $this->assertCount(1, $infoAboutClientResult); - - self::assertEquals( - 'CONTACT', - $infoAboutClientResult[0]->CRM_ENTITY_TYPE, - sprintf( - 'name type incorrect, expected: CONTACT , and your type: %s', - $infoAboutClientResult[0]->CRM_ENTITY_TYPE - ) - ); - - $this->assertEquals($contactId, $infoAboutClientResult[0]->CRM_ENTITY_ID); - - $this->contactService->delete($contactId); - } - - /** - * @throws TransportException - * @throws BaseException - * @throws Exception - * @covers ExternalCall::searchCrmEntities - */ - public function testSearchCrmEntitiesLeadFound(): void - { - //Зарегистрированный лид - $phoneNumberLead = sprintf('+7%s%s', time(), random_int(1, PHP_INT_MAX)); - $leadId1 = $this->leadService->add( - [ - 'TITLE' => 'ИП Титов', - 'NAME' => 'Кирилл', - 'PHONE' => [ - [ - 'VALUE' => $phoneNumberLead, - 'VALUE_TYPE' => 'WORK', - ], - ], - ] - )->getId(); - $infoAboutLeadResult = $this->externalCallService->searchCrmEntities($phoneNumberLead)->getCrmEntitiesSearchResult(); - $this->assertCount(1, $infoAboutLeadResult); - - self::assertEquals( - 'LEAD', - $infoAboutLeadResult[0]->CRM_ENTITY_TYPE, - sprintf('name type incorrect, expected: LEAD , and your type: %s', $infoAboutLeadResult[0]->CRM_ENTITY_TYPE) - ); - $this->leadService->delete($leadId1); - } - - /** - * @throws TransportException - * @throws BaseException - * @throws Exception - * @covers ExternalCall::searchCrmEntities - */ - public function testSearchCrmEntitiesMultipleContactsFound(): void - { - $contactPhone = sprintf('+7%s%s', time(), random_int(1, PHP_INT_MAX)); - $contactId1 = $this->contactService->add( - [ - 'NAME' => 'Глеб', - 'SECOND_NAME' => 'Егорович', - 'PHONE' => [ - [ - 'VALUE' => $contactPhone, - 'VALUE_TYPE' => 'WORK', - ], - ], - ] - )->getId(); - $contactId2 = $this->contactService->add( - [ - 'NAME' => 'Хлеб', - 'SECOND_NAME' => 'Олегович', - 'PHONE' => [ - [ - 'VALUE' => $contactPhone, - 'VALUE_TYPE' => 'WORK', - ], - ], - ] - )->getId(); - $contactIds = [$contactId1, $contactId2]; - $this->externalCallService->searchCrmEntities($contactPhone)->getCrmEntitiesSearchResult(); - $this->assertTrue(in_array($contactId1, $contactIds, true)); - $this->contactService->delete($contactId1); - $this->contactService->delete($contactId2); - } - - /** - * @throws Exception - * @covers ExternalCall::searchCrmEntities - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException - */ - public function testSearchCrmEntitiesWithDifferentPhonePrefix(): void - { - $phoneBody = sprintf('+7%s%s', time(), random_int(1, PHP_INT_MAX)); - $contactPhone1 = sprintf('+7%s', $phoneBody); - $contactPhone2 = sprintf('+8%s', $phoneBody); - $contactId1 = $this->contactService->add( - [ - 'NAME' => 'Глеб', - 'SECOND_NAME' => 'Егорович', - 'PHONE' => [ - [ - 'VALUE' => $contactPhone1, - 'VALUE_TYPE' => 'WORK', - ], - ], - ] - )->getId(); - - $infoAboutTwoContactsResult1 = $this->externalCallService->searchCrmEntities($contactPhone1)->getCrmEntitiesSearchResult(); - $infoAboutTwoContactsResult2 = $this->externalCallService->searchCrmEntities($contactPhone2)->getCrmEntitiesSearchResult(); - $infoAboutTwoContactsResult3 = $this->externalCallService->searchCrmEntities($phoneBody)->getCrmEntitiesSearchResult(); - $this->assertEquals($contactId1, $infoAboutTwoContactsResult1[0]->CRM_ENTITY_ID); - $this->assertEmpty($infoAboutTwoContactsResult2); - $this->assertEmpty($infoAboutTwoContactsResult3); - $this->contactService->delete($contactId1); - } - - /** - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException - */ - public function setUp(): void - { - $this->externalCallService = Fabric::getServiceBuilder()->getTelephonyScope()->externalCall(); - $this->leadService = Fabric::getServiceBuilder()->getCRMScope()->lead(); - $this->contactService = Fabric::getServiceBuilder()->getCRMScope()->contact(); - } - -} \ No newline at end of file diff --git a/tests/Integration/Services/Telephony/Service/assets/test-phone-record.mp3 b/tests/Integration/Services/Telephony/Service/assets/test-phone-record.mp3 deleted file mode 100644 index ad8f97381376d1abbfc22bfaecbe5e6dfd188e8f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 160954 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�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≷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�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 Date: Tue, 28 May 2024 01:47:22 +0600 Subject: [PATCH 029/138] delete all telephony services Signed-off-by: mesilov --- src/Services/Telephony/Service/Call.php | 48 ----- .../Telephony/Service/ExternalCall.php | 198 ------------------ .../Telephony/Service/ExternalLine.php | 110 ---------- .../Telephony/TelephonyServiceBuilder.php | 59 ------ 4 files changed, 415 deletions(-) delete mode 100644 src/Services/Telephony/Service/Call.php delete mode 100644 src/Services/Telephony/Service/ExternalCall.php delete mode 100644 src/Services/Telephony/Service/ExternalLine.php delete mode 100644 src/Services/Telephony/TelephonyServiceBuilder.php diff --git a/src/Services/Telephony/Service/Call.php b/src/Services/Telephony/Service/Call.php deleted file mode 100644 index f24be08f..00000000 --- a/src/Services/Telephony/Service/Call.php +++ /dev/null @@ -1,48 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\SDK\Services\Telephony\Service; - -use Bitrix24\SDK\Services\AbstractService; -use Bitrix24\SDK\Services\Telephony\Result\CallAttachTranscriptionResult; -use Money\Money; - - -class Call extends AbstractService -{ - /** - * The method adds a call transcript. - * - * @param string $callId - * @param Money $callCosts - * @param array> $messages - * @return \Bitrix24\SDK\Services\Telephony\Result\CallAttachTranscriptionResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException - * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_call_attachtranscription.php - */ - public function attachTranscription(string $callId, Money $callCosts, array $messages): CallAttachTranscriptionResult - { - return new CallAttachTranscriptionResult( - $this->core->call( - 'telephony.call.attachTranscription', - [ - 'CALL_ID' => $callId, - 'COST' => $this->decimalMoneyFormatter->format($callCosts), - 'COST_CURRENCY' => $callCosts->getCurrency()->getCode(), - 'MESSAGES' => $messages, - ] - ) - ); - } -} \ No newline at end of file diff --git a/src/Services/Telephony/Service/ExternalCall.php b/src/Services/Telephony/Service/ExternalCall.php deleted file mode 100644 index 96993fb9..00000000 --- a/src/Services/Telephony/Service/ExternalCall.php +++ /dev/null @@ -1,198 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\SDK\Services\Telephony\Service; - -use Bitrix24\SDK\Services\AbstractService; -use Bitrix24\SDK\Services\Telephony\Result\ExternalCallFinishResult; -use Bitrix24\SDK\Services\Telephony\Result\ExternalCallRecordResult; -use Bitrix24\SDK\Services\Telephony\Result\ExternalCallRegisterResult; -use Bitrix24\SDK\Services\Telephony\Result\ExternalCallHideResult; -use Bitrix24\SDK\Services\Telephony\Result\ExternalCallSearchCrmEntitiesResult; -use Bitrix24\SDK\Services\Telephony\Result\ExternalCallShowResult; - - -class ExternalCall extends AbstractService -{ - /** - * The method registers a call in Bitrix24 - * - * @param array{ - * USER_PHONE_INNER?: string, - * USER_ID?: int, - * PHONE_NUMBER?: string, - * CALL_START_DATE?: string, - * CRM_CREATE?: int, - * CRM_SOURCE?: string, - * CRM_ENTITY_TYPE?: string, - * CRM_ENTITY_ID?: int, - * SHOW?: int, - * CALL_LIST_ID?: int, - * LINE_NUMBER?: string, - * TYPE?: int, - * } $fields - * - * - * @return \Bitrix24\SDK\Services\Telephony\Result\ExternalCallRegisterResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException - * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_register.php - */ - - public function registerCall(array $fields): ExternalCallRegisterResult - { - return new ExternalCallRegisterResult( - $this->core->call( - 'telephony.externalcall.register', - $fields, - ) - ); - } - - /** - * This method displays a call ID screen to the user. - * - * - * @param string $callId - * @param int $userId - * - * @return \Bitrix24\SDK\Services\Telephony\Result\ExternalCallShowResult - * - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException - * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_show.php - */ - public function show(string $callId, int $userId): ExternalCallShowResult - { - return new ExternalCallShowResult( - $this->core->call( - 'telephony.externalcall.show', - [ - 'CALL_ID' => $callId, - 'USER_ID' => $userId, - ] - ) - ); - } - - /** - * This method hides call information window. - * - * - * @param string $callId - * @param int $userId - * - * @return \Bitrix24\SDK\Services\Telephony\Result\ExternalCallHideResult - * - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_hide.php - */ - public function hide(string $callId, int $userId): ExternalCallHideResult - { - return new ExternalCallHideResult( - $this->core->call( - 'telephony.externalcall.hide', - [ - 'CALL_ID' => $callId, - 'USER_ID' => $userId, - ] - ) - ); - } - - /** - * Method completes the call, registers it in the statistics and hides the call ID screen from the user. - * - * @param array{ - * CALL_ID?: string, - * USER_ID?: int, - * DURATION?: int, - * COST?: double, - * COST_CURRENCY?: string, - * STATUS_CODE?: string, - * FAILED_REASON?: string, - * RECORD_URL?: string, - * VOTE?: int, - * ADD_TO_CHAT?: int, - * } $fields - * - * @return ExternalCallFinishResult - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_finish.php - */ - public function finish(array $fields): ExternalCallFinishResult - { - return new ExternalCallFinishResult( - $this->core->call( - 'telephony.externalcall.finish', - $fields - ) - ); - } - - /** - * This method connects a record to a finished call and to the call Activity. - * - * @param string $callId - * @param string $fileName - * @param string $fileContent - * @param string|null $recordUrl - * - * @return ExternalCallRecordResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException - * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalCall_attachRecord.php - */ - public function attachRecord(string $callId, string $fileName, string $fileContent, ?string $recordUrl = null): ExternalCallRecordResult - { - return new ExternalCallRecordResult( - $this->core->call( - 'telephony.externalCall.attachRecord', - [ - 'CALL_ID' => $callId, - 'FILENAME' => $fileName, - 'FILE_CONTENT' => $fileContent, - 'RECORD_URL' => $recordUrl, - ] - ) - ); - } - - /** - * This method allows to retrieve information about a client from CRM by a telephone number via single request. - * - * If CRM has duplicates by phone, method find and return ONLY one of duplicates - * Method do NOT FIND phones with different phone prefixes +7 or +8 or without it, all phones must by standardised - * - * @param string $phoneNumber - * - * @return ExternalCallSearchCrmEntitiesResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException - * https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalCall_searchCrmEntities.php - */ - - public function searchCrmEntities(string $phoneNumber): ExternalCallSearchCrmEntitiesResult - { - return new ExternalCallSearchCrmEntitiesResult( - $this->core->call( - 'telephony.externalCall.searchCrmEntities', - [ - 'PHONE_NUMBER'=>$phoneNumber, - ] - ) - ); - } -} \ No newline at end of file diff --git a/src/Services/Telephony/Service/ExternalLine.php b/src/Services/Telephony/Service/ExternalLine.php deleted file mode 100644 index 056a6a49..00000000 --- a/src/Services/Telephony/Service/ExternalLine.php +++ /dev/null @@ -1,110 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\SDK\Services\Telephony\Service; - -use Bitrix24\SDK\Services\AbstractService; -use Bitrix24\SDK\Services\Telephony\Result\ExternalLineAddResult; -use Bitrix24\SDK\Services\Telephony\Result\ExternalLinesResult; -use Bitrix24\SDK\Services\Telephony\Result\ExternalLineDeleteResult; -use Bitrix24\SDK\Services\Telephony\Result\ExternalLineUpdateResult; - - -class ExternalLine extends AbstractService{ - /** - * The method adds an outer line - * - * @param string $lineNumber - * @param string $nameLine - * - * @return \Bitrix24\SDK\Services\Telephony\Result\ExternalLineAddResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException - * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalLine_add.php - */ - - public function add(string $lineNumber , string $nameLine): ExternalLineAddResult - { - return new ExternalLineAddResult( - $this->core->call( - 'telephony.externalLine.add', - [ - 'NUMBER' => $lineNumber, - 'NAME' => $nameLine, - ] - ) - ); - } - - /** - * The method adds an outer line - * - * @return ExternalLinesResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException - * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalLine_get.php - */ - - public function get(): ExternalLinesResult - { - return new ExternalLinesResult( - $this->core->call('telephony.externalLine.get') - ); - } - - /** - * The method allows you to change the name of the external line - * - * @param string $lineNumber - * @param string $newLineName - * - * @return ExternalLineUpdateResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException - * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalLine_update.php - */ - - public function update(string $lineNumber, string $newLineName): ExternalLineUpdateResult - { - return new ExternalLineUpdateResult( - $this->core->call('telephony.externalLine.update', - [ - 'NUMBER' => $lineNumber, - 'NAME' => $newLineName, - ] - ) - ); - } - - /** - * The method for removing an external line. - * - * @param string $lineNumber - * - * @return ExternalLineDeleteResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException - * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalLine_delete.php - */ - - public function delete(string $lineNumber): ExternalLineDeleteResult - { - return new ExternalLineDeleteResult( - $this->core->call('telephony.externalLine.delete', - [ - 'NUMBER' => $lineNumber, - ] - ) - ); - } -} \ No newline at end of file diff --git a/src/Services/Telephony/TelephonyServiceBuilder.php b/src/Services/Telephony/TelephonyServiceBuilder.php deleted file mode 100644 index 1891a0e3..00000000 --- a/src/Services/Telephony/TelephonyServiceBuilder.php +++ /dev/null @@ -1,59 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Bitrix24\SDK\Services\Telephony; - -use Bitrix24\SDK\Services\AbstractServiceBuilder; -use Bitrix24\SDK\Services\Telephony\Service\Call; -use Bitrix24\SDK\Services\Telephony\Service\ExternalLine; -use Bitrix24\SDK\Services\Telephony\Service\ExternalCall; - - -class TelephonyServiceBuilder extends AbstractServiceBuilder -{ - /** - * @return ExternalLine - */ - public function externalLine(): ExternalLine - { - if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new ExternalLine($this->core, $this->log); - } - - return $this->serviceCache[__METHOD__]; - } - - /** - * @return ExternalCall - */ - public function externalCall(): ExternalCall - { - if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new ExternalCall($this->core, $this->log); - } - - return $this->serviceCache[__METHOD__]; - } - - /** - * @return Call - */ - public function call(): Call - { - if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new Call($this->core, $this->log); - } - - return $this->serviceCache[__METHOD__]; - } - -} \ No newline at end of file From 378a8337e653efa21fe433e853e71f66ba351196 Mon Sep 17 00:00:00 2001 From: mesilov Date: Tue, 28 May 2024 01:48:15 +0600 Subject: [PATCH 030/138] delete telephony service builder Signed-off-by: mesilov --- src/Services/ServiceBuilder.php | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/Services/ServiceBuilder.php b/src/Services/ServiceBuilder.php index ad7615ca..eee8ae91 100644 --- a/src/Services/ServiceBuilder.php +++ b/src/Services/ServiceBuilder.php @@ -110,18 +110,6 @@ public function getCatalogScope(): CatalogServiceBuilder return $this->serviceCache[__METHOD__]; } - /** - * @return TelephonyServiceBuilder - */ - public function getTelephonyScope(): TelephonyServiceBuilder - { - if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new TelephonyServiceBuilder($this->core, $this->batch, $this->bulkItemsReader, $this->log); - } - - return $this->serviceCache[__METHOD__]; - } - public function getBizProcScope(): WorkflowsServiceBuilder { if (!isset($this->serviceCache[__METHOD__])) { From b1d649767af73d0515f2ba9f30b2b2b9bb78b60e Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 29 May 2024 01:56:48 +0600 Subject: [PATCH 031/138] Add new enums and services to Telephony scope Introduced `CallType` and `CrmEntityType` within the `Telephony\Common` namespace, providing enum definitions for call and CRM entity types. Also added `TelephonyServiceBuilder` for Telephony related service construction, along with a new `ExternalCall` service under `Telephony\ExternalCall\Service`. All changes are reflected in the updated CHANGELOG. Signed-off-by: mesilov --- CHANGELOG.md | 5 +++- src/Services/Telephony/Common/CallType.php | 13 ++++++++++ .../Telephony/Common/CrmEntityType.php | 12 ++++++++++ .../Telephony/ExternalCall/Service/Batch.php | 17 +++++++++++++ .../Telephony/TelephonyServiceBuilder.php | 24 +++++++++++++++++++ 5 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 src/Services/Telephony/Common/CallType.php create mode 100644 src/Services/Telephony/Common/CrmEntityType.php create mode 100644 src/Services/Telephony/ExternalCall/Service/Batch.php create mode 100644 src/Services/Telephony/TelephonyServiceBuilder.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 356635b7..6b9991fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,8 +47,11 @@ * add [Rector](https://github.com/rectorphp/rector) for improve code quality and speed up releases cycle ### Changed -* update scope `telephony`, scope fully rewritten +* update scope `telephony`, scope fully rewritten + * `ExternalCall` – work with external call + * add `CallType` – call types enum + * add `CrmEntityType` – crm entity type enum ## 2.0-beta.2 — 1.04.2024 diff --git a/src/Services/Telephony/Common/CallType.php b/src/Services/Telephony/Common/CallType.php new file mode 100644 index 00000000..1ff4fe89 --- /dev/null +++ b/src/Services/Telephony/Common/CallType.php @@ -0,0 +1,13 @@ +serviceCache[__METHOD__])) { + $this->serviceCache[__METHOD__] = new Telephony\ExternalCall\Service\ExternalCall( + new Telephony\ExternalCall\Service\Batch($this->batch, $this->log), + $this->core, + $this->log + ); + } + + return $this->serviceCache[__METHOD__]; + } +} \ No newline at end of file From 8f23aaa9f57d6e27b302d776461a85b0b208c34b Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 30 May 2024 01:59:12 +0600 Subject: [PATCH 032/138] Add telephony external call service and improve error handling Added a new service for handling external calls in the telephony section. This feature enables registering calls in Bitrix24, including objects that correspond to numbers in CRM. Also improved error handling by adding a new exception for scenarios where a user is not found or is not active. Removed redundant comments in ServiceBuilder.php and added a test for the new service. Signed-off-by: mesilov --- CHANGELOG.md | 1 + src/Core/ApiLevelErrorHandler.php | 9 +- .../UserNotFoundOrIsNotActiveException.php | 9 ++ src/Services/ServiceBuilder.php | 24 ++-- src/Services/Telephony/Common/CrmEntity.php | 15 +++ .../ExternalCallRegisteredItemResult.php | 47 ++++++++ .../Result/ExternalCallRegisteredResult.php | 15 +++ .../ExternalCall/Service/ExternalCall.php | 105 ++++++++++++++++++ .../ExternalCall/Service/ExternalCallTest.php | 66 +++++++++++ 9 files changed, 275 insertions(+), 16 deletions(-) create mode 100644 src/Core/Exceptions/UserNotFoundOrIsNotActiveException.php create mode 100644 src/Services/Telephony/Common/CrmEntity.php create mode 100644 src/Services/Telephony/ExternalCall/Result/ExternalCallRegisteredItemResult.php create mode 100644 src/Services/Telephony/ExternalCall/Result/ExternalCallRegisteredResult.php create mode 100644 src/Services/Telephony/ExternalCall/Service/ExternalCall.php create mode 100644 tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b9991fd..1eb97641 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ * add `IncomingRobotRequest` wrapper for data from crm-robot request * add `IncomingWorkflowRequest` wrapper for data from biz proc activity request * add [Rector](https://github.com/rectorphp/rector) for improve code quality and speed up releases cycle +* add `Bitrix24\SDK\Core\Exceptions\UserNotFoundOrIsNotActiveException` exception if user not found, or it is not active ### Changed diff --git a/src/Core/ApiLevelErrorHandler.php b/src/Core/ApiLevelErrorHandler.php index a580f8d4..817c5f63 100644 --- a/src/Core/ApiLevelErrorHandler.php +++ b/src/Core/ApiLevelErrorHandler.php @@ -10,6 +10,7 @@ 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\Services\Workflows\Exceptions\ActivityOrRobotAlreadyInstalledException; use Bitrix24\SDK\Services\Workflows\Exceptions\ActivityOrRobotValidationFailureException; use Bitrix24\SDK\Services\Workflows\Exceptions\WorkflowTaskAlreadyCompletedException; @@ -83,13 +84,17 @@ private function handleError(array $responseBody, ?string $batchCommandId = null if ($batchCommandId !== null) { $batchErrorPrefix = sprintf(' batch command id: %s', $batchCommandId); } - // fix error code responses + // 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': @@ -109,6 +114,8 @@ private function handleError(array $responseBody, ?string $batchCommandId = null 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)); default: throw new BaseException(sprintf('%s - %s %s', $errorCode, $errorDescription, $batchErrorPrefix)); } diff --git a/src/Core/Exceptions/UserNotFoundOrIsNotActiveException.php b/src/Core/Exceptions/UserNotFoundOrIsNotActiveException.php new file mode 100644 index 00000000..fbaefb1b --- /dev/null +++ b/src/Core/Exceptions/UserNotFoundOrIsNotActiveException.php @@ -0,0 +1,9 @@ +serviceCache[__METHOD__])) { @@ -29,9 +26,6 @@ public function getCRMScope(): CRMServiceBuilder return $this->serviceCache[__METHOD__]; } - /** - * @return IMServiceBuilder - */ public function getIMScope(): IMServiceBuilder { if (!isset($this->serviceCache[__METHOD__])) { @@ -41,9 +35,6 @@ public function getIMScope(): IMServiceBuilder return $this->serviceCache[__METHOD__]; } - /** - * @return IMOpenLinesServiceBuilder - */ public function getIMOpenLinesScope(): IMOpenLinesServiceBuilder { if (!isset($this->serviceCache[__METHOD__])) { @@ -65,9 +56,6 @@ public function getMainScope(): MainServiceBuilder return $this->serviceCache[__METHOD__]; } - /** - * @return UserConsentServiceBuilder - */ public function getUserConsentScope(): UserConsentServiceBuilder { if (!isset($this->serviceCache[__METHOD__])) { @@ -77,9 +65,6 @@ public function getUserConsentScope(): UserConsentServiceBuilder return $this->serviceCache[__METHOD__]; } - /** - * @return UserServiceBuilder - */ public function getUserScope(): UserServiceBuilder { if (!isset($this->serviceCache[__METHOD__])) { @@ -118,4 +103,13 @@ public function getBizProcScope(): WorkflowsServiceBuilder 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/Telephony/Common/CrmEntity.php b/src/Services/Telephony/Common/CrmEntity.php new file mode 100644 index 00000000..d8db3879 --- /dev/null +++ b/src/Services/Telephony/Common/CrmEntity.php @@ -0,0 +1,15 @@ +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..b43696f1 --- /dev/null +++ b/src/Services/Telephony/ExternalCall/Result/ExternalCallRegisteredResult.php @@ -0,0 +1,15 @@ +getCoreResponse()->getResponseData()->getResult()); + } +} \ 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..2747f8fb --- /dev/null +++ b/src/Services/Telephony/ExternalCall/Service/ExternalCall.php @@ -0,0 +1,105 @@ +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 ? 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, + ]) + ); + } + +} \ 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..d873c9f9 --- /dev/null +++ b/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php @@ -0,0 +1,66 @@ +sb->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()->ID; + // set inner phone number + $this->sb->getUserScope()->user()->update( + $currentB24UserId, + [ + 'UF_PHONE_INNER' => $innerPhoneNumber + ] + ); + + $res = $this->externalCall->register( + '111123', + $currentB24UserId, + $phoneNumber, + CarbonImmutable::now(), + Telephony\Common\CallType::outbound, + true, + true, + '3333', + null, + Telephony\Common\CrmEntityType::contact + + ); + + $this->assertNotEmpty($res->getExternalCallRegistered()->CALL_ID); + } + + + public function setUp(): void + { + $this->externalCall = Fabric::getServiceBuilder(true)->getTelephonyScope()->externalCall(); + $this->sb = Fabric::getServiceBuilder(true); + } +} \ No newline at end of file From 5335a32fe43f14f888b62bc33110953e986d397a Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 3 Jun 2024 01:21:16 +0600 Subject: [PATCH 033/138] Update "ExternalCall" service with new features for telephony module This update to the "ExternalCall" service adds advanced telephony functionality. The revised service now includes methods for handling call records, CRM entity retrieval, completion of calls, and interaction with the call UI. Exception handling has been improved with more specific error types and some minor changes have made to response and parameter types for better accuracy and clarity. Signed-off-by: mesilov --- CHANGELOG.md | 11 +- src/Core/Result/AbstractItem.php | 13 +- .../Result/UserInterfaceDialogCallResult.php | 19 ++ .../Filesystem/Base64Encoder.php | 33 ++- .../Common/TelephonyCallStatusCode.php | 20 ++ .../CallRecordFileUploadedItemResult.php | 20 ++ .../Result/CallRecordFileUploadedResult.php | 15 ++ .../Result/ExternalCallFinishedItemResult.php | 71 ++++++ .../Result/ExternalCallFinishedResult.php | 15 ++ .../Result/SearchCrmEntitiesItemResult.php | 33 +++ .../Result/SearchCrmEntitiesResult.php | 24 ++ .../Result/UserDigestItemResult.php | 29 +++ .../ExternalCall/Service/ExternalCall.php | 226 +++++++++++++++++- .../Telephony/TelephonyServiceBuilder.php | 7 + 14 files changed, 519 insertions(+), 17 deletions(-) create mode 100644 src/Core/Result/UserInterfaceDialogCallResult.php create mode 100644 src/Services/Telephony/Common/TelephonyCallStatusCode.php create mode 100644 src/Services/Telephony/ExternalCall/Result/CallRecordFileUploadedItemResult.php create mode 100644 src/Services/Telephony/ExternalCall/Result/CallRecordFileUploadedResult.php create mode 100644 src/Services/Telephony/ExternalCall/Result/ExternalCallFinishedItemResult.php create mode 100644 src/Services/Telephony/ExternalCall/Result/ExternalCallFinishedResult.php create mode 100644 src/Services/Telephony/ExternalCall/Result/SearchCrmEntitiesItemResult.php create mode 100644 src/Services/Telephony/ExternalCall/Result/SearchCrmEntitiesResult.php create mode 100644 src/Services/Telephony/ExternalCall/Result/UserDigestItemResult.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 1eb97641..6ce8a9d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,7 @@ * add method `Bitrix24\SDK\Core\Credentials\AccessToken::initFromWorkflowRequest` * 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\Result\UserInterfaceDialogCallResult` result of call UI * add `IncomingRobotRequest` wrapper for data from crm-robot request * add `IncomingWorkflowRequest` wrapper for data from biz proc activity request * add [Rector](https://github.com/rectorphp/rector) for improve code quality and speed up releases cycle @@ -50,7 +51,15 @@ ### Changed * update scope `telephony`, scope fully rewritten - * `ExternalCall` – work with external call + * `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 * add `CallType` – call types enum * add `CrmEntityType` – crm entity type enum diff --git a/src/Core/Result/AbstractItem.php b/src/Core/Result/AbstractItem.php index a3e3e409..5522a869 100644 --- a/src/Core/Result/AbstractItem.php +++ b/src/Core/Result/AbstractItem.php @@ -7,6 +7,8 @@ use ArrayIterator; use Bitrix24\SDK\Core\Exceptions\ImmutableResultViolationException; use IteratorAggregate; +use Money\Currencies\ISOCurrencies; +use Money\Parser\DecimalMoneyParser; use Traversable; /** @@ -17,15 +19,12 @@ abstract class AbstractItem implements IteratorAggregate { protected array $data; + protected DecimalMoneyParser $decimalMoneyParser; - /** - * AbstractItem constructor. - * - * @param array $data - */ public function __construct(array $data) { $this->data = $data; + $this->decimalMoneyParser = new DecimalMoneyParser(new ISOCurrencies()); } /** @@ -50,7 +49,7 @@ public function __get($offset) /** * @param int|string $offset - * @param mixed $value + * @param mixed $value * * @return void * @throws ImmutableResultViolationException @@ -74,7 +73,7 @@ public function __unset($offset) /** * {@inheritdoc} */ - public function getIterator():Traversable + public function getIterator(): Traversable { return new ArrayIterator($this->data); } diff --git a/src/Core/Result/UserInterfaceDialogCallResult.php b/src/Core/Result/UserInterfaceDialogCallResult.php new file mode 100644 index 00000000..1e12f581 --- /dev/null +++ b/src/Core/Result/UserInterfaceDialogCallResult.php @@ -0,0 +1,19 @@ +getCoreResponse()->getResponseData()->getResult()[0]; + } +} \ No newline at end of file diff --git a/src/Infrastructure/Filesystem/Base64Encoder.php b/src/Infrastructure/Filesystem/Base64Encoder.php index e02aa41d..a13387bb 100644 --- a/src/Infrastructure/Filesystem/Base64Encoder.php +++ b/src/Infrastructure/Filesystem/Base64Encoder.php @@ -9,12 +9,43 @@ 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; } /** @@ -35,7 +66,7 @@ public function encodeFile(string $filename): string $fileBody = $this->base64Encoder->encodeString($fileBody); - $this->log->debug('encodeFile.finish¨'); + $this->log->debug('encodeFile.finish'); return $fileBody; } } \ 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..d07bb2de --- /dev/null +++ b/src/Services/Telephony/Common/TelephonyCallStatusCode.php @@ -0,0 +1,20 @@ +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..ff1d0d00 --- /dev/null +++ b/src/Services/Telephony/ExternalCall/Result/ExternalCallFinishedItemResult.php @@ -0,0 +1,71 @@ +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..fcd8aa1c --- /dev/null +++ b/src/Services/Telephony/ExternalCall/Result/ExternalCallFinishedResult.php @@ -0,0 +1,15 @@ +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..1dac45d2 --- /dev/null +++ b/src/Services/Telephony/ExternalCall/Result/SearchCrmEntitiesItemResult.php @@ -0,0 +1,33 @@ +data[$offset]); + case 'CRM_ENTITY_ID': + case 'ASSIGNED_BY_ID': + return (int)$this->data[$offset]; + case 'ASSIGNED_BY': + return new UserDigestItemResult($this->data[$offset]); + default: + return $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..bd6bc1e9 --- /dev/null +++ b/src/Services/Telephony/ExternalCall/Result/SearchCrmEntitiesResult.php @@ -0,0 +1,24 @@ +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..8eb876c2 --- /dev/null +++ b/src/Services/Telephony/ExternalCall/Result/UserDigestItemResult.php @@ -0,0 +1,29 @@ + (int)$this->data[$offset], + default => $this->data[$offset] ?? null, + }; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/ExternalCall/Service/ExternalCall.php b/src/Services/Telephony/ExternalCall/Service/ExternalCall.php index 2747f8fb..c7b6cc77 100644 --- a/src/Services/Telephony/ExternalCall/Service/ExternalCall.php +++ b/src/Services/Telephony/ExternalCall/Service/ExternalCall.php @@ -6,25 +6,83 @@ use Bitrix24\SDK\Core\Contracts\CoreInterface; use Bitrix24\SDK\Core\Exceptions\BaseException; +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\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; class ExternalCall extends AbstractService { public function __construct( - readonly public Batch $batch, - CoreInterface $core, - LoggerInterface $log + readonly public Batch $batch, + private readonly Base64Encoder $base64Encoder, + CoreInterface $core, + LoggerInterface $log ) { parent::__construct($core, $log); } + /** + * Get url for upload call record + * + * @param non-empty-string $callId + * @param non-empty-string $callRecordFileName + * @return CallRecordFileUploadedResult + * @throws BaseException + * @throws InvalidArgumentException + * @throws TransportException + * @throws \Bitrix24\SDK\Core\Exceptions\FileNotFoundException + * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalCall_attachRecord.php + */ + public function getCallRecordUploadUrl( + string $callId, + string $callRecordFileName, + ): CallRecordFileUploadedResult + { + return new CallRecordFileUploadedResult($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 + * @return CallRecordFileUploadedResult + * @throws BaseException + * @throws InvalidArgumentException + * @throws TransportException + * @throws \Bitrix24\SDK\Core\Exceptions\FileNotFoundException + * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalCall_attachRecord.php + */ + 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. * @@ -44,9 +102,9 @@ public function __construct( * * To create a call "activity", it is also necessary to call the telephony.externalcall.finish method * - * @param string $userInnerPhoneNumber Internal number of the user. Required. - * @param int $b24UserId User ID. Required. - * @param string $phoneNumber Telephone number. Required + * @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 @@ -57,8 +115,8 @@ public function __construct( * @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 string|null $lineNumber Number of external line, via which the call was made (see. telephony.externalLine.add). Optional. - * @param string|null $sourceId STATUS_ID of the source from the source selection list. + * @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 @@ -102,4 +160,156 @@ public function register( ); } + /** + * 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 + */ + 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 Money $callCost + * @param TelephonyCallStatusCode $callStatus + * @param bool $isAddCallToChat + * @param non-empty-string|null $failedReason + * @param int|null $userVote + * @return ExternalCallFinishedResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_finish.php + */ + public function finishForUserPhoneInner( + string $callId, + string $userInnerPhoneNumber, + int $duration, + Money $callCost, + TelephonyCallStatusCode $callStatus, + 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($callCost), + 'COST_CURRENCY' => $callCost->getCurrency()->getCode(), + 'STATUS_CODE' => $callStatus->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 Money $callCost + * @param TelephonyCallStatusCode $callStatus + * @param bool $isAddCallToChat + * @param non-empty-string|null $failedReason + * @param int|null $userVote + * @return ExternalCallFinishedResult + * @throws BaseException + * @throws TransportException + * @see https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_finish.php + */ + public function finishForUserId( + string $callId, + int $b24UserId, + int $duration, + Money $callCost, + TelephonyCallStatusCode $callStatus, + 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($callCost), + 'COST_CURRENCY' => $callCost->getCurrency()->getCode(), + 'STATUS_CODE' => $callStatus->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 + * @return UserInterfaceDialogCallResult + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_show.php + */ + 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 + * @return UserInterfaceDialogCallResult + * @throws BaseException + * @throws TransportException + * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_hide.php + */ + 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/TelephonyServiceBuilder.php b/src/Services/Telephony/TelephonyServiceBuilder.php index 8d9c4e47..4131d046 100644 --- a/src/Services/Telephony/TelephonyServiceBuilder.php +++ b/src/Services/Telephony/TelephonyServiceBuilder.php @@ -4,8 +4,10 @@ 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 { @@ -14,6 +16,11 @@ 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 ); From ef4fbbeaa1599ee00809bf5e32c29a5527397a16 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 3 Jun 2024 02:43:28 +0600 Subject: [PATCH 034/138] Refine telephony services and improve test coverage This commit refines the implemented telephony services, notably by improving the call record functionality and adding FileNotFoundException. Two new classes, CallRecordUploadUrlResult and CallRecordUploadUrlItemResult, were added. PHPUnit coverage was also expanded, with tests for hiding, showing, and finishing calls added to the ExternalCallTest class. Signed-off-by: mesilov --- rector.php | 7 +- .../CallRecordFileUploadedItemResult.php | 3 +- .../Result/CallRecordUploadUrlItemResult.php | 15 ++ .../Result/CallRecordUploadUrlResult.php | 15 ++ .../ExternalCall/Service/ExternalCall.php | 12 +- .../ExternalCall/Service/ExternalCallTest.php | 160 +++++++++++++++++- .../ExternalCall/Service/call-record-test.mp3 | Bin 0 -> 52244 bytes 7 files changed, 199 insertions(+), 13 deletions(-) create mode 100644 src/Services/Telephony/ExternalCall/Result/CallRecordUploadUrlItemResult.php create mode 100644 src/Services/Telephony/ExternalCall/Result/CallRecordUploadUrlResult.php create mode 100644 tests/Integration/Services/Telephony/ExternalCall/Service/call-record-test.mp3 diff --git a/rector.php b/rector.php index 5bd131ec..17728066 100644 --- a/rector.php +++ b/rector.php @@ -3,15 +3,20 @@ declare(strict_types=1); use Rector\Config\RectorConfig; +use Rector\PHPUnit\Set\PHPUnitSetList; use Rector\Set\ValueObject\DowngradeLevelSetList; use Rector\TypeDeclaration\Rector\ClassMethod\AddVoidReturnTypeWhereNoReturnRector; return RectorConfig::configure() ->withPaths([ __DIR__ . '/src/Services/Workflows', + __DIR__ . '/tests/Integration/Services/Telephony', ]) ->withSets( - [DowngradeLevelSetList::DOWN_TO_PHP_82] + [ + DowngradeLevelSetList::DOWN_TO_PHP_82, + PHPUnitSetList::PHPUNIT_100 + ] ) ->withPhpSets( php82: true // 8.2 diff --git a/src/Services/Telephony/ExternalCall/Result/CallRecordFileUploadedItemResult.php b/src/Services/Telephony/ExternalCall/Result/CallRecordFileUploadedItemResult.php index 1d86dfab..cabaee3f 100644 --- a/src/Services/Telephony/ExternalCall/Result/CallRecordFileUploadedItemResult.php +++ b/src/Services/Telephony/ExternalCall/Result/CallRecordFileUploadedItemResult.php @@ -12,8 +12,7 @@ use Money\Parser\DecimalMoneyParser; /** - * @property-read non-empty-string $uploadUrl - * @property-read non-empty-string $fieldName + * @property-read int $FILE_ID */ class CallRecordFileUploadedItemResult extends AbstractItem { diff --git a/src/Services/Telephony/ExternalCall/Result/CallRecordUploadUrlItemResult.php b/src/Services/Telephony/ExternalCall/Result/CallRecordUploadUrlItemResult.php new file mode 100644 index 00000000..ea4c35c3 --- /dev/null +++ b/src/Services/Telephony/ExternalCall/Result/CallRecordUploadUrlItemResult.php @@ -0,0 +1,15 @@ +getCoreResponse()->getResponseData()->getResult()); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/ExternalCall/Service/ExternalCall.php b/src/Services/Telephony/ExternalCall/Service/ExternalCall.php index c7b6cc77..62ef17b6 100644 --- a/src/Services/Telephony/ExternalCall/Service/ExternalCall.php +++ b/src/Services/Telephony/ExternalCall/Service/ExternalCall.php @@ -6,6 +6,7 @@ use Bitrix24\SDK\Core\Contracts\CoreInterface; 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; @@ -15,6 +16,7 @@ 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; @@ -39,19 +41,19 @@ public function __construct( * * @param non-empty-string $callId * @param non-empty-string $callRecordFileName - * @return CallRecordFileUploadedResult + * @return CallRecordUploadUrlResult * @throws BaseException * @throws InvalidArgumentException * @throws TransportException - * @throws \Bitrix24\SDK\Core\Exceptions\FileNotFoundException + * @throws FileNotFoundException * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalCall_attachRecord.php */ public function getCallRecordUploadUrl( string $callId, string $callRecordFileName, - ): CallRecordFileUploadedResult + ): CallRecordUploadUrlResult { - return new CallRecordFileUploadedResult($this->core->call('telephony.externalCall.attachRecord', [ + return new CallRecordUploadUrlResult($this->core->call('telephony.externalCall.attachRecord', [ 'CALL_ID' => $callId, 'FILENAME' => pathinfo($callRecordFileName, PATHINFO_BASENAME), 'FILE_CONTENT' => null @@ -67,7 +69,7 @@ public function getCallRecordUploadUrl( * @throws BaseException * @throws InvalidArgumentException * @throws TransportException - * @throws \Bitrix24\SDK\Core\Exceptions\FileNotFoundException + * @throws FileNotFoundException * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalCall_attachRecord.php */ public function attachCallRecordInBase64( diff --git a/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php b/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php index d873c9f9..5b4975a4 100644 --- a/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php +++ b/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php @@ -5,32 +5,84 @@ 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; +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 Telephony\ExternalCall\Service\ExternalCall $externalCall; + private ExternalCall $externalCall; private ServiceBuilder $sb; + /** + * @throws RandomException + * @throws InvalidArgumentException + * @throws BaseException + * @throws TransportException + */ + public static function callIdDataProvider(): Generator + { + $externalCall = Fabric::getServiceBuilder()->getTelephonyScope()->externalCall(); + $sb = Fabric::getServiceBuilder(); + + $innerPhoneNumber = '123'; + // phone number to call + $phoneNumber = sprintf('7978' . random_int(1000000, 9999999)); + $currentB24UserId = $sb->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()->ID; + // set inner phone number + $sb->getUserScope()->user()->update( + $currentB24UserId, + [ + 'UF_PHONE_INNER' => $innerPhoneNumber + ] + ); + $res = $externalCall->register( + $innerPhoneNumber, + $currentB24UserId, + $phoneNumber, + CarbonImmutable::now(), + Telephony\Common\CallType::outbound, + true, + true, + '3333', + null, + Telephony\Common\CrmEntityType::contact + + ); + + yield 'default callId' => [ + $res->getExternalCallRegistered()->CALL_ID, + $currentB24UserId + ]; + } + /** * @return void * @throws BaseException * @throws TransportException - * @covers \Bitrix24\SDK\Services\Telephony\ExternalCall\Service\ExternalCall::register - * @testdox Method registers a call in Bitrix24. */ + #[Test] + #[TestDox('Method registers a call in Bitrix24.')] public function testRegister(): void { $innerPhoneNumber = '123'; // phone number to call $phoneNumber = '79780000000'; - //todo set userInnerPhone number $currentB24UserId = $this->sb->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()->ID; // set inner phone number $this->sb->getUserScope()->user()->update( @@ -41,7 +93,7 @@ public function testRegister(): void ); $res = $this->externalCall->register( - '111123', + $innerPhoneNumber, $currentB24UserId, $phoneNumber, CarbonImmutable::now(), @@ -57,6 +109,104 @@ public function testRegister(): void $this->assertNotEmpty($res->getExternalCallRegistered()->CALL_ID); } + /** + * @param string $callId + * @param int $currentB24UserId + * @return void + * @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 + { + $cost = new Money(10000, new Currency('USD')); + $duration = 100; + + $fr = $this->externalCall->finishForUserId( + $callId, + $currentB24UserId, + $duration, + $cost, + Telephony\Common\TelephonyCallStatusCode::successful, + true + ); + + $this->assertTrue($fr->getExternalCallFinished()->COST->equals($cost)); + $this->assertEquals($fr->getExternalCallFinished()->CALL_DURATION, $duration); + + } + + #[Test] + #[DataProvider('callIdDataProvider')] + #[TestDox('Method tests attachCallRecordInBase64 method')] + public function testAttachRecordInBase64(string $callId, int $currentB24UserId): void + { + $cost = new Money(10000, new Currency('USD')); + $duration = 100; + $fr = $this->externalCall->finishForUserId( + $callId, + $currentB24UserId, + $duration, + $cost, + Telephony\Common\TelephonyCallStatusCode::successful, + true + ); + $filename = __DIR__ . '/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 + { + $fr = $this->externalCall->finishForUserId( + $callId, + $currentB24UserId, + 100, + new Money(10000, new Currency('USD')), + Telephony\Common\TelephonyCallStatusCode::successful, + true + ); + + $filename = __DIR__ . '/call-record-test.mp3'; + $this->assertStringContainsString('https://', $this->externalCall->getCallRecordUploadUrl( + $callId, + $filename + )->getUploadUrlResult()->uploadUrl); + + } + + public function testSearchCrmEntities(): void + { + $res = $this->externalCall->searchCrmEntities('79780000000'); + $this->assertGreaterThanOrEqual(0, count($res->getCrmEntities())); + } public function setUp(): void { diff --git a/tests/Integration/Services/Telephony/ExternalCall/Service/call-record-test.mp3 b/tests/Integration/Services/Telephony/ExternalCall/Service/call-record-test.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..58cec68622cb217acd5815634106a1f4883e113d GIT binary patch literal 52244 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 Date: Sat, 15 Jun 2024 13:35:10 +0600 Subject: [PATCH 035/138] Add call transcript functionality to Telephony service This update introduces the ability to add a call transcript to the Telephony service. A new test has been added for this feature, along with various new classes to handle transcript information, such as TranscriptMessage and TranscriptMessageSide. The TelephonyServiceBuilder has also been updated to include call services. Signed-off-by: mesilov --- CHANGELOG.md | 4 + .../Result/TranscriptAttachItemResult.php | 15 ++ .../Call/Result/TranscriptAttachedResult.php | 15 ++ src/Services/Telephony/Call/Service/Batch.php | 17 +++ src/Services/Telephony/Call/Service/Call.php | 87 ++++++++++++ .../Telephony/Common/TranscriptMessage.php | 17 +++ .../Common/TranscriptMessageSide.php | 11 ++ .../Telephony/TelephonyServiceBuilder.php | 12 ++ .../Telephony/Call/Service/CallTest.php | 131 ++++++++++++++++++ .../ExternalCall/Service/ExternalCallTest.php | 4 +- .../Service => }/call-record-test.mp3 | Bin 11 files changed, 311 insertions(+), 2 deletions(-) create mode 100644 src/Services/Telephony/Call/Result/TranscriptAttachItemResult.php create mode 100644 src/Services/Telephony/Call/Result/TranscriptAttachedResult.php create mode 100644 src/Services/Telephony/Call/Service/Batch.php create mode 100644 src/Services/Telephony/Call/Service/Call.php create mode 100644 src/Services/Telephony/Common/TranscriptMessage.php create mode 100644 src/Services/Telephony/Common/TranscriptMessageSide.php create mode 100644 tests/Integration/Services/Telephony/Call/Service/CallTest.php rename tests/Integration/Services/Telephony/{ExternalCall/Service => }/call-record-test.mp3 (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ce8a9d0..1a5b9e3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,6 +60,10 @@ * `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 + * 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 diff --git a/src/Services/Telephony/Call/Result/TranscriptAttachItemResult.php b/src/Services/Telephony/Call/Result/TranscriptAttachItemResult.php new file mode 100644 index 00000000..580ce0a6 --- /dev/null +++ b/src/Services/Telephony/Call/Result/TranscriptAttachItemResult.php @@ -0,0 +1,15 @@ +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..970df4af --- /dev/null +++ b/src/Services/Telephony/Call/Service/Batch.php @@ -0,0 +1,17 @@ + $item->side->value, + 'START_TIME' => $item->startTime, + 'STOP_TIME' => $item->stopTime, + 'MESSAGE' => $item->message + ]; + } + return new TranscriptAttachedResult($this->core->call('telephony.call.attachTranscription', [ + 'CALL_ID' => $callId, + 'COST' => $this->decimalMoneyFormatter->format($cost), + 'COST_CURRENCY' => $cost->getCurrency()->getCode(), + 'MESSAGES' => $rawMessages + ])); + } +} + + + + + + + + + + + + + + + + + diff --git a/src/Services/Telephony/Common/TranscriptMessage.php b/src/Services/Telephony/Common/TranscriptMessage.php new file mode 100644 index 00000000..80ce22be --- /dev/null +++ b/src/Services/Telephony/Common/TranscriptMessage.php @@ -0,0 +1,17 @@ +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__]; } } \ 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..99143682 --- /dev/null +++ b/tests/Integration/Services/Telephony/Call/Service/CallTest.php @@ -0,0 +1,131 @@ +getTelephonyScope()->externalCall(); + $sb = Fabric::getServiceBuilder(); + + $innerPhoneNumber = '123'; + // phone number to call + $phoneNumber = sprintf('7978' . random_int(1000000, 9999999)); + $currentB24UserId = $sb->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()->ID; + // set inner phone number + $sb->getUserScope()->user()->update( + $currentB24UserId, + [ + 'UF_PHONE_INNER' => $innerPhoneNumber + ] + ); + $res = $externalCall->register( + $innerPhoneNumber, + $currentB24UserId, + $phoneNumber, + CarbonImmutable::now(), + Telephony\Common\CallType::outbound, + true, + true, + '3333', + null, + Telephony\Common\CrmEntityType::contact + + ); + + yield 'default callId' => [ + $res->getExternalCallRegistered()->CALL_ID, + $currentB24UserId + ]; + } + + /** + * @throws TransportException + * @throws BaseException + */ + #[Test] + #[DataProvider('callIdDataProvider')] + #[TestDox('Method tests attachTranscription method')] + public function testFinishWithUserId(string $callId, int $currentB24UserId): void + { + $cost = new Money(30000, new Currency('USD')); + $duration = 100; + + $this->externalCall->finishForUserId( + $callId, + $currentB24UserId, + $duration, + $cost, + Telephony\Common\TelephonyCallStatusCode::successful, + true + ); + + $filename = dirname(__DIR__, 2) . '/call-record-test.mp3'; + $this->externalCall->attachCallRecordInBase64( + $callId, + $filename + ); + + $res = $this->call->attachTranscription( + $callId, + $cost, + [ + 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, $res->getTranscriptAttachItem()->TRANSCRIPT_ID); + } + + public function setUp(): void + { + $this->call = Fabric::getServiceBuilder(true)->getTelephonyScope()->call(); + $this->externalCall = Fabric::getServiceBuilder(true)->getTelephonyScope()->externalCall(); + $this->sb = Fabric::getServiceBuilder(true); + } +} \ 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 index 5b4975a4..126cb640 100644 --- a/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php +++ b/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php @@ -173,7 +173,7 @@ public function testAttachRecordInBase64(string $callId, int $currentB24UserId): Telephony\Common\TelephonyCallStatusCode::successful, true ); - $filename = __DIR__ . '/call-record-test.mp3'; + $filename = dirname(__DIR__,2) . '/call-record-test.mp3'; $this->assertGreaterThan(0, $this->externalCall->attachCallRecordInBase64( $callId, $filename @@ -194,7 +194,7 @@ public function testGetCallRecordUploadUrl(string $callId, int $currentB24UserId true ); - $filename = __DIR__ . '/call-record-test.mp3'; + $filename = dirname(__DIR__,2) . '/call-record-test.mp3'; $this->assertStringContainsString('https://', $this->externalCall->getCallRecordUploadUrl( $callId, $filename diff --git a/tests/Integration/Services/Telephony/ExternalCall/Service/call-record-test.mp3 b/tests/Integration/Services/Telephony/call-record-test.mp3 similarity index 100% rename from tests/Integration/Services/Telephony/ExternalCall/Service/call-record-test.mp3 rename to tests/Integration/Services/Telephony/call-record-test.mp3 From d877b9f86c2ed42623f2d69c36f5edab3a835cca Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 15 Jun 2024 13:44:17 +0600 Subject: [PATCH 036/138] Remove destructor in Response.php The destructor was removed from the Response.php file because it included logging that was deemed unnecessary. The associated logging for responseInfo, networkTimings, and restTimings was relying on possibly uninvoked getResponseData method and an unfinished asynchronous request. This operation makes the logic of the code more straightforward and avoid redundancy. Signed-off-by: mesilov --- src/Core/Response/Response.php | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/Core/Response/Response.php b/src/Core/Response/Response.php index d25c64a6..7129653c 100644 --- a/src/Core/Response/Response.php +++ b/src/Core/Response/Response.php @@ -62,27 +62,6 @@ public function getApiCommand(): Command return $this->apiCommand; } - public function __destruct() - { - // пишем эту информацию в деструкторе, т.к. метод getResponseData может и не быть вызван - // логировать в конструкторе смысла нет, т.к. запрос ещё может не завершиться из-за того, - // что он асинхронный и неблокирующий - $restTimings = null; - if ($this->responseData !== null) { - $restTimings = [ - 'rest_query_duration' => $this->responseData->getTime()->getDuration(), - 'rest_query_processing' => $this->responseData->getTime()->getProcessing(), - 'rest_query_start' => $this->responseData->getTime()->getStart(), - 'rest_query_finish' => $this->responseData->getTime()->getFinish(), - ]; - } - $this->logger->info('Response.TransportInfo', [ - 'restTimings' => $restTimings, - 'networkTimings' => (new NetworkTimingsParser($this->httpResponse->getInfo()))->toArrayWithMicroseconds(), - 'responseInfo' => (new ResponseInfoParser($this->httpResponse->getInfo()))->toArray(), - ]); - } - /** * @return DTO\ResponseData * @throws BaseException From 9bfbc930fd92676d74d4605b6dc1f28601413e48 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 15 Jun 2024 13:44:38 +0600 Subject: [PATCH 037/138] Add new integration test suite for telephony scope The Makefile and phpunit.xml.dist have been updated to include a new PHPUnit test suite. This dedicated test suite focuses on the integration tests for telephony scope. The aim is to segregate and improve the manageability of tests related to telephony. Signed-off-by: mesilov --- Makefile | 5 ++++- phpunit.xml.dist | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 22233389..bd2b9f31 100644 --- a/Makefile +++ b/Makefile @@ -10,4 +10,7 @@ lint-rector-fix: vendor/bin/rector process test-unit: - vendor/bin/phpunit --testsuite unit_tests \ No newline at end of file + vendor/bin/phpunit --testsuite unit_tests + +test-integration-scope-telephony: + vendor/bin/phpunit --testsuite integration_tests_scope_telephony \ No newline at end of file diff --git a/phpunit.xml.dist b/phpunit.xml.dist index eb16a1a7..2ff7c987 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -10,6 +10,9 @@ ./tests/Integration + + ./tests/Integration/Services/Telephony/ + From 27de7c689a2aff55d9c74ac76e52e38dcb080ce3 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 15 Jun 2024 13:50:21 +0600 Subject: [PATCH 038/138] Change data type of CONTACT_ID and CONTACT_IDS The data type of `CONTACT_ID` and `CONTACT_IDS` has been changed from string to int and array of ints respectively in CRM Deal Service. This is to ensure the consistency and appropriateness of the data types used across the service. Signed-off-by: mesilov --- src/Services/CRM/Deal/Service/Batch.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Services/CRM/Deal/Service/Batch.php b/src/Services/CRM/Deal/Service/Batch.php index 6be17a0a..c7234694 100644 --- a/src/Services/CRM/Deal/Service/Batch.php +++ b/src/Services/CRM/Deal/Service/Batch.php @@ -55,8 +55,8 @@ public function __construct(BatchOperationsInterface $batch, LoggerInterface $lo * IS_MANUAL_OPPORTUNITY?: string, * TAX_VALUE?: string, * COMPANY_ID?: string, - * CONTACT_ID?: string, - * CONTACT_IDS?: string, + * CONTACT_ID?: int, + * CONTACT_IDS?: int[], * QUOTE_ID?: string, * BEGINDATE?: string, * CLOSEDATE?: string, @@ -167,8 +167,8 @@ public function list(array $order, array $filter, array $select, ?int $limit = n * IS_MANUAL_OPPORTUNITY?: string, * TAX_VALUE?: string, * COMPANY_ID?: string, - * CONTACT_ID?: string, - * CONTACT_IDS?: string, + * CONTACT_ID?: int, + * CONTACT_IDS?: int[], * QUOTE_ID?: string, * BEGINDATE?: string, * CLOSEDATE?: string, From 464f68c1a000ec4497bc49ff6bb4d9664edb8262 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 15 Jun 2024 13:55:46 +0600 Subject: [PATCH 039/138] Refactor variable and function names in telephony tests The commit primarily addresses the renaming of variables and adjusting the visibility of setUp functions in the Telephony test classes. Variables such as '$sb' and '$cost' have been renamed to more meaningful names like '$serviceBuilder' and '$money'. The visibility of 'setUp' functions has been changed from public to protected for better encapsulation. Signed-off-by: mesilov --- .../Telephony/Call/Service/CallTest.php | 19 ++++----- .../ExternalCall/Service/ExternalCallTest.php | 41 +++++++++---------- 2 files changed, 28 insertions(+), 32 deletions(-) diff --git a/tests/Integration/Services/Telephony/Call/Service/CallTest.php b/tests/Integration/Services/Telephony/Call/Service/CallTest.php index 99143682..2feb9469 100644 --- a/tests/Integration/Services/Telephony/Call/Service/CallTest.php +++ b/tests/Integration/Services/Telephony/Call/Service/CallTest.php @@ -28,8 +28,8 @@ class CallTest extends TestCase { private Telephony\Call\Service\Call $call; + private ExternalCall $externalCall; - private ServiceBuilder $sb; /** * @throws RandomException @@ -40,14 +40,14 @@ class CallTest extends TestCase public static function callIdDataProvider(): Generator { $externalCall = Fabric::getServiceBuilder()->getTelephonyScope()->externalCall(); - $sb = Fabric::getServiceBuilder(); + $serviceBuilder = Fabric::getServiceBuilder(); $innerPhoneNumber = '123'; // phone number to call - $phoneNumber = sprintf('7978' . random_int(1000000, 9999999)); - $currentB24UserId = $sb->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()->ID; + $phoneNumber = '7978' . random_int(1000000, 9999999); + $currentB24UserId = $serviceBuilder->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()->ID; // set inner phone number - $sb->getUserScope()->user()->update( + $serviceBuilder->getUserScope()->user()->update( $currentB24UserId, [ 'UF_PHONE_INNER' => $innerPhoneNumber @@ -82,14 +82,14 @@ public static function callIdDataProvider(): Generator #[TestDox('Method tests attachTranscription method')] public function testFinishWithUserId(string $callId, int $currentB24UserId): void { - $cost = new Money(30000, new Currency('USD')); + $money = new Money(30000, new Currency('USD')); $duration = 100; $this->externalCall->finishForUserId( $callId, $currentB24UserId, $duration, - $cost, + $money, Telephony\Common\TelephonyCallStatusCode::successful, true ); @@ -102,7 +102,7 @@ public function testFinishWithUserId(string $callId, int $currentB24UserId): voi $res = $this->call->attachTranscription( $callId, - $cost, + $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)"), @@ -122,10 +122,9 @@ public function testFinishWithUserId(string $callId, int $currentB24UserId): voi $this->assertGreaterThan(0, $res->getTranscriptAttachItem()->TRANSCRIPT_ID); } - public function setUp(): void + protected function setUp(): void { $this->call = Fabric::getServiceBuilder(true)->getTelephonyScope()->call(); $this->externalCall = Fabric::getServiceBuilder(true)->getTelephonyScope()->externalCall(); - $this->sb = Fabric::getServiceBuilder(true); } } \ 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 index 126cb640..304d338a 100644 --- a/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php +++ b/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php @@ -26,7 +26,8 @@ class ExternalCallTest extends TestCase { private ExternalCall $externalCall; - private ServiceBuilder $sb; + + private ServiceBuilder $serviceBuilder; /** * @throws RandomException @@ -37,14 +38,14 @@ class ExternalCallTest extends TestCase public static function callIdDataProvider(): Generator { $externalCall = Fabric::getServiceBuilder()->getTelephonyScope()->externalCall(); - $sb = Fabric::getServiceBuilder(); + $serviceBuilder = Fabric::getServiceBuilder(); $innerPhoneNumber = '123'; // phone number to call - $phoneNumber = sprintf('7978' . random_int(1000000, 9999999)); - $currentB24UserId = $sb->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()->ID; + $phoneNumber = '7978' . random_int(1000000, 9999999); + $currentB24UserId = $serviceBuilder->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()->ID; // set inner phone number - $sb->getUserScope()->user()->update( + $serviceBuilder->getUserScope()->user()->update( $currentB24UserId, [ 'UF_PHONE_INNER' => $innerPhoneNumber @@ -71,7 +72,6 @@ public static function callIdDataProvider(): Generator } /** - * @return void * @throws BaseException * @throws TransportException */ @@ -83,9 +83,9 @@ public function testRegister(): void // phone number to call $phoneNumber = '79780000000'; - $currentB24UserId = $this->sb->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()->ID; + $currentB24UserId = $this->serviceBuilder->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()->ID; // set inner phone number - $this->sb->getUserScope()->user()->update( + $this->serviceBuilder->getUserScope()->user()->update( $currentB24UserId, [ 'UF_PHONE_INNER' => $innerPhoneNumber @@ -110,9 +110,6 @@ public function testRegister(): void } /** - * @param string $callId - * @param int $currentB24UserId - * @return void * @throws BaseException * @throws TransportException */ @@ -141,19 +138,19 @@ public function testHide(string $callId, int $currentB24UserId): void #[TestDox('Method tests finishForUserId method')] public function testFinishWithUserId(string $callId, int $currentB24UserId): void { - $cost = new Money(10000, new Currency('USD')); + $money = new Money(10000, new Currency('USD')); $duration = 100; $fr = $this->externalCall->finishForUserId( $callId, $currentB24UserId, $duration, - $cost, + $money, Telephony\Common\TelephonyCallStatusCode::successful, true ); - $this->assertTrue($fr->getExternalCallFinished()->COST->equals($cost)); + $this->assertTrue($fr->getExternalCallFinished()->COST->equals($money)); $this->assertEquals($fr->getExternalCallFinished()->CALL_DURATION, $duration); } @@ -163,13 +160,13 @@ public function testFinishWithUserId(string $callId, int $currentB24UserId): voi #[TestDox('Method tests attachCallRecordInBase64 method')] public function testAttachRecordInBase64(string $callId, int $currentB24UserId): void { - $cost = new Money(10000, new Currency('USD')); + $money = new Money(10000, new Currency('USD')); $duration = 100; - $fr = $this->externalCall->finishForUserId( + $this->externalCall->finishForUserId( $callId, $currentB24UserId, $duration, - $cost, + $money, Telephony\Common\TelephonyCallStatusCode::successful, true ); @@ -185,7 +182,7 @@ public function testAttachRecordInBase64(string $callId, int $currentB24UserId): #[TestDox('Method tests getCallRecordUploadUrl method')] public function testGetCallRecordUploadUrl(string $callId, int $currentB24UserId): void { - $fr = $this->externalCall->finishForUserId( + $this->externalCall->finishForUserId( $callId, $currentB24UserId, 100, @@ -204,13 +201,13 @@ public function testGetCallRecordUploadUrl(string $callId, int $currentB24UserId public function testSearchCrmEntities(): void { - $res = $this->externalCall->searchCrmEntities('79780000000'); - $this->assertGreaterThanOrEqual(0, count($res->getCrmEntities())); + $searchCrmEntitiesResult = $this->externalCall->searchCrmEntities('79780000000'); + $this->assertGreaterThanOrEqual(0, count($searchCrmEntitiesResult->getCrmEntities())); } - public function setUp(): void + protected function setUp(): void { $this->externalCall = Fabric::getServiceBuilder(true)->getTelephonyScope()->externalCall(); - $this->sb = Fabric::getServiceBuilder(true); + $this->serviceBuilder = Fabric::getServiceBuilder(true); } } \ No newline at end of file From d84705b67524216aa62115daf9fc544469ccce1b Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 15 Jun 2024 16:34:30 +0600 Subject: [PATCH 040/138] Add telephony external line service and tests This commit introduces a new service for managing telephony external lines, complete with unit tests. Changes include adding a new test suite for workflow integrations and creating new files for the telephony external line service, batch operations, and relevant test cases. Signed-off-by: mesilov --- Makefile | 5 +- phpunit.xml.dist | 3 + .../Result/ExternalLineAddItemResult.php | 15 ++++ .../Result/ExternalLineAddedResult.php | 15 ++++ .../Telephony/ExternalLine/Service/Batch.php | 17 ++++ .../ExternalLine/Service/ExternalLine.php | 59 ++++++++++++ .../Telephony/TelephonyServiceBuilder.php | 14 +++ .../ExternalLine/Service/ExternalLineTest.php | 90 +++++++++++++++++++ 8 files changed, 217 insertions(+), 1 deletion(-) create mode 100644 src/Services/Telephony/ExternalLine/Result/ExternalLineAddItemResult.php create mode 100644 src/Services/Telephony/ExternalLine/Result/ExternalLineAddedResult.php create mode 100644 src/Services/Telephony/ExternalLine/Service/Batch.php create mode 100644 src/Services/Telephony/ExternalLine/Service/ExternalLine.php create mode 100644 tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php diff --git a/Makefile b/Makefile index bd2b9f31..c21aa058 100644 --- a/Makefile +++ b/Makefile @@ -12,5 +12,8 @@ lint-rector-fix: test-unit: vendor/bin/phpunit --testsuite unit_tests +# integration tests with granularity by api-scope test-integration-scope-telephony: - vendor/bin/phpunit --testsuite integration_tests_scope_telephony \ No newline at end of file + vendor/bin/phpunit --testsuite integration_tests_scope_telephony +test-integration-scope-workflows: + vendor/bin/phpunit --testsuite integration_tests_scope_workflows \ No newline at end of file diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 2ff7c987..3555dd5e 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -13,6 +13,9 @@ ./tests/Integration/Services/Telephony/ + + ./tests/Integration/Services/Workflows/ + diff --git a/src/Services/Telephony/ExternalLine/Result/ExternalLineAddItemResult.php b/src/Services/Telephony/ExternalLine/Result/ExternalLineAddItemResult.php new file mode 100644 index 00000000..2dbd4cf6 --- /dev/null +++ b/src/Services/Telephony/ExternalLine/Result/ExternalLineAddItemResult.php @@ -0,0 +1,15 @@ +getCoreResponse()->getResponseData()->getResult()); + } +} \ 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..2bf29666 --- /dev/null +++ b/src/Services/Telephony/ExternalLine/Service/Batch.php @@ -0,0 +1,17 @@ +core->call('telephony.externalLine.add', [ + 'NUMBER' => $lineNumber, + 'NAME' => $lineName, + 'CRM_AUTO_CREATE' => $isAutoCreateCrmEntities ? 'Y' : 'N' + ])); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/TelephonyServiceBuilder.php b/src/Services/Telephony/TelephonyServiceBuilder.php index 661845ff..3523e20e 100644 --- a/src/Services/Telephony/TelephonyServiceBuilder.php +++ b/src/Services/Telephony/TelephonyServiceBuilder.php @@ -28,6 +28,7 @@ public function externalCall(): Telephony\ExternalCall\Service\ExternalCall return $this->serviceCache[__METHOD__]; } + public function call(): Telephony\Call\Service\Call { if (!isset($this->serviceCache[__METHOD__])) { @@ -40,4 +41,17 @@ public function call(): Telephony\Call\Service\Call 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__]; + } } \ 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..d48de16e --- /dev/null +++ b/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php @@ -0,0 +1,90 @@ +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 + ] + ); + $res = $externalCall->register( + $innerPhoneNumber, + $currentB24UserId, + $phoneNumber, + CarbonImmutable::now(), + Telephony\Common\CallType::outbound, + true, + true, + '3333', + null, + Telephony\Common\CrmEntityType::contact + + ); + + yield 'default callId' => [ + $res->getExternalCallRegistered()->CALL_ID, + $currentB24UserId + ]; + } + + /** + * @throws TransportException + * @throws BaseException + */ + #[Test] + #[TestDox('Method tests add external line method')] + public function testExternalLineAdd(): void + { + $lineNumber = (string)time(); + $res = $this->externalLine->add($lineNumber, true, sprintf('line-name-%s', $lineNumber)); + $this->assertGreaterThan(0, $res->getExternalLineAddResultItem()->ID); + } + + protected function setUp(): void + { + $this->externalLine = Fabric::getServiceBuilder(true)->getTelephonyScope()->externalLine(); + } +} \ No newline at end of file From f55101542a776500ea1236bd9ca07f018fe78a86 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 15 Jun 2024 16:51:27 +0600 Subject: [PATCH 041/138] Add method to retrieve list of external lines A new method has been added to the ExternalLine service to retrieve the list of external lines of an application. Alongside, new result classes ExternalLineItemResult and ExternalLinesResult have been created. Additionally, configuration in rector.php has been adjusted for cache and rule sets management. Signed-off-by: mesilov --- rector.php | 16 +++++++++---- .../Result/ExternalLineItemResult.php | 24 +++++++++++++++++++ .../Result/ExternalLinesResult.php | 19 +++++++++++++++ .../ExternalLine/Service/ExternalLine.php | 13 ++++++++++ 4 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 src/Services/Telephony/ExternalLine/Result/ExternalLineItemResult.php create mode 100644 src/Services/Telephony/ExternalLine/Result/ExternalLinesResult.php diff --git a/rector.php b/rector.php index 17728066..e0c8690c 100644 --- a/rector.php +++ b/rector.php @@ -5,13 +5,13 @@ use Rector\Config\RectorConfig; use Rector\PHPUnit\Set\PHPUnitSetList; use Rector\Set\ValueObject\DowngradeLevelSetList; -use Rector\TypeDeclaration\Rector\ClassMethod\AddVoidReturnTypeWhereNoReturnRector; return RectorConfig::configure() ->withPaths([ __DIR__ . '/src/Services/Workflows', __DIR__ . '/tests/Integration/Services/Telephony', ]) + ->withCache(cacheDirectory: __DIR__ . '.cache/rector') ->withSets( [ DowngradeLevelSetList::DOWN_TO_PHP_82, @@ -21,6 +21,14 @@ ->withPhpSets( php82: true // 8.2 ) - ->withRules([ - AddVoidReturnTypeWhereNoReturnRector::class, - ]); \ No newline at end of file + ->withPreparedSets( + deadCode: true, + codeQuality: true, + codingStyle: true, + typeDeclarations: true, + privatization: true, + naming: true, + instanceOf: true, + earlyReturn: true, + strictBooleans: true + ); \ 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..8fd4109e --- /dev/null +++ b/src/Services/Telephony/ExternalLine/Result/ExternalLineItemResult.php @@ -0,0 +1,24 @@ + $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..7df1f728 --- /dev/null +++ b/src/Services/Telephony/ExternalLine/Result/ExternalLinesResult.php @@ -0,0 +1,19 @@ +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/ExternalLine.php b/src/Services/Telephony/ExternalLine/Service/ExternalLine.php index e4c98d0b..7dbfc7c0 100644 --- a/src/Services/Telephony/ExternalLine/Service/ExternalLine.php +++ b/src/Services/Telephony/ExternalLine/Service/ExternalLine.php @@ -21,6 +21,7 @@ use Bitrix24\SDK\Services\Telephony\ExternalCall\Result\ExternalCallRegisteredResult; use Bitrix24\SDK\Services\Telephony\ExternalCall\Result\SearchCrmEntitiesResult; use Bitrix24\SDK\Services\Telephony\ExternalLine\Result\ExternalLineAddedResult; +use Bitrix24\SDK\Services\Telephony\ExternalLine\Result\ExternalLinesResult; use Bitrix24\SDK\Services\Telephony\ExternalLine\Service\Batch; use Carbon\CarbonImmutable; use Money\Money; @@ -56,4 +57,16 @@ public function add(string $lineNumber, bool $isAutoCreateCrmEntities = true, ?s 'CRM_AUTO_CREATE' => $isAutoCreateCrmEntities ? 'Y' : 'N' ])); } + + /** + * 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 + */ + public function get(): ExternalLinesResult + { + return new ExternalLinesResult($this->core->call('telephony.externalLine.get')); + } } \ No newline at end of file From a6fecbaaa0be48220795a7ed4ee28f25c24dc8c7 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 15 Jun 2024 17:34:33 +0600 Subject: [PATCH 042/138] Add delete method in ExternalLine service A delete method has been implemented in the ExternalLine service, which allows to delete an external line. The method is tested in the ExternalLineTest class where a line is added, verified, deleted, and the deletion is confirmed. A new result object, EmptyResult, has been introduced to cover cases where a function doesn't return any specific data. Signed-off-by: mesilov --- src/Core/Result/EmptyResult.php | 12 ++++ .../ExternalLine/Service/ExternalLine.php | 18 +++++ .../ExternalLine/Service/ExternalLineTest.php | 72 ++++++++----------- 3 files changed, 58 insertions(+), 44 deletions(-) create mode 100644 src/Core/Result/EmptyResult.php diff --git a/src/Core/Result/EmptyResult.php b/src/Core/Result/EmptyResult.php new file mode 100644 index 00000000..faccdbec --- /dev/null +++ b/src/Core/Result/EmptyResult.php @@ -0,0 +1,12 @@ +core->call('telephony.externalLine.delete', [ + 'NUMBER' => $lineNumber + ])); + } + /** * Method allows to retrieve the list of external lines of an application. * diff --git a/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php b/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php index d48de16e..8fc4ef2c 100644 --- a/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php +++ b/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php @@ -11,6 +11,7 @@ use Bitrix24\SDK\Services\Telephony; use Bitrix24\SDK\Services\Telephony\Common\TranscriptMessage; use Bitrix24\SDK\Services\Telephony\Common\TranscriptMessageSide; +use Bitrix24\SDK\Services\Telephony\ExternalLine\Service\ExternalLine; use Bitrix24\SDK\Tests\Integration\Fabric; use Carbon\CarbonImmutable; use Generator; @@ -23,52 +24,11 @@ use PHPUnit\Framework\TestCase; use Random\RandomException; -#[CoversClass(Telephony\ExternalLine\Service\ExternalLine::class)] +#[CoversClass(ExternalLine::class)] +#[CoversClass(ExternalLine::class)] class ExternalLineTest extends TestCase { - private Telephony\ExternalLine\Service\ExternalLine $externalLine; - - /** - * @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 - ] - ); - $res = $externalCall->register( - $innerPhoneNumber, - $currentB24UserId, - $phoneNumber, - CarbonImmutable::now(), - Telephony\Common\CallType::outbound, - true, - true, - '3333', - null, - Telephony\Common\CrmEntityType::contact - - ); - - yield 'default callId' => [ - $res->getExternalCallRegistered()->CALL_ID, - $currentB24UserId - ]; - } + private ExternalLine $externalLine; /** * @throws TransportException @@ -81,6 +41,30 @@ public function testExternalLineAdd(): void $lineNumber = (string)time(); $res = $this->externalLine->add($lineNumber, true, sprintf('line-name-%s', $lineNumber)); $this->assertGreaterThan(0, $res->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())); + } + + #[Test] + #[TestDox('Method tests delete external line method')] + public function testDeleteExternalLine(): void + { + $lineNumber = (string)time(); + $this->externalLine->add($lineNumber, true, sprintf('line-name-%s', $lineNumber)); + + $this->assertContains($lineNumber, array_column($this->externalLine->get()->getExternalLines(), 'NUMBER')); + + $deleteRes = $this->externalLine->delete($lineNumber); + $this->assertEquals([], $deleteRes->getCoreResponse()->getResponseData()->getResult()); + + $this->assertNotContains($lineNumber, array_column($this->externalLine->get()->getExternalLines(), 'NUMBER')); } protected function setUp(): void From 19ba7cd9c779d7d63ebc15215898885b96b72b38 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 15 Jun 2024 17:47:41 +0600 Subject: [PATCH 043/138] Refactor Telephony unit tests and improve external line features Removed unnecessary imports and reorganized the code in Telephony service unit tests, ensuring a cleaner and more maintainable structure. Also enhanced the external line functionalities, refining the methods for adding and deleting an external line. Furthermore, changes in the import process have been made in the Rector configuration for more efficient handling of unused imports. Signed-off-by: mesilov --- CHANGELOG.md | 4 ++++ rector.php | 4 ++++ .../Telephony/Call/Service/CallTest.php | 3 +-- .../ExternalCall/Service/ExternalCallTest.php | 2 +- .../ExternalLine/Service/ExternalLineTest.php | 20 ++++++++----------- 5 files changed, 18 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a5b9e3c..0436688f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,6 +62,10 @@ * `hide` – hides call information window * `Call` – work with call: * `attachTranscription` – method adds a call transcript + * `Call` – work with external line: + * `add` – method adds an external line + * `delete` – method delete external line + * `get` – method gets external lines list * add `TranscriptMessage` – data structure for transcript message item * add `TranscriptMessageSide` – enum for describe side of diarization * add `CallType` – call types enum diff --git a/rector.php b/rector.php index e0c8690c..ba79510c 100644 --- a/rector.php +++ b/rector.php @@ -18,6 +18,10 @@ PHPUnitSetList::PHPUNIT_100 ] ) + ->withImportNames( + importNames: false, + removeUnusedImports: true + ) ->withPhpSets( php82: true // 8.2 ) diff --git a/tests/Integration/Services/Telephony/Call/Service/CallTest.php b/tests/Integration/Services/Telephony/Call/Service/CallTest.php index 2feb9469..9218b388 100644 --- a/tests/Integration/Services/Telephony/Call/Service/CallTest.php +++ b/tests/Integration/Services/Telephony/Call/Service/CallTest.php @@ -7,8 +7,6 @@ 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; use Bitrix24\SDK\Services\Telephony\Common\TranscriptMessage; use Bitrix24\SDK\Services\Telephony\Common\TranscriptMessageSide; use Bitrix24\SDK\Services\Telephony\ExternalCall\Service\ExternalCall; @@ -23,6 +21,7 @@ use PHPUnit\Framework\Attributes\TestDox; use PHPUnit\Framework\TestCase; use Random\RandomException; +use Bitrix24\SDK\Services\Telephony; #[CoversClass(Telephony\Call\Service\Call::class)] class CallTest extends TestCase diff --git a/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php b/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php index 304d338a..d7ad18eb 100644 --- a/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php +++ b/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php @@ -8,8 +8,8 @@ use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; use Bitrix24\SDK\Core\Exceptions\TransportException; use Bitrix24\SDK\Services\ServiceBuilder; -use Bitrix24\SDK\Services\Telephony; use Bitrix24\SDK\Services\Telephony\ExternalCall\Service\ExternalCall; +use Bitrix24\SDK\Services\Telephony; use Bitrix24\SDK\Tests\Integration\Fabric; use Carbon\CarbonImmutable; use Generator; diff --git a/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php b/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php index 8fc4ef2c..0cfab2bb 100644 --- a/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php +++ b/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php @@ -5,20 +5,10 @@ namespace Bitrix24\SDK\Tests\Integration\Services\Telephony\ExternalLine\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; -use Bitrix24\SDK\Services\Telephony\Common\TranscriptMessage; -use Bitrix24\SDK\Services\Telephony\Common\TranscriptMessageSide; use Bitrix24\SDK\Services\Telephony\ExternalLine\Service\ExternalLine; 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; @@ -33,12 +23,13 @@ class ExternalLineTest extends TestCase /** * @throws TransportException * @throws BaseException + * @throws RandomException */ #[Test] #[TestDox('Method tests add external line method')] public function testExternalLineAdd(): void { - $lineNumber = (string)time(); + $lineNumber = (string)time() . abs(random_int(PHP_INT_MIN, PHP_INT_MAX)); $res = $this->externalLine->add($lineNumber, true, sprintf('line-name-%s', $lineNumber)); $this->assertGreaterThan(0, $res->getExternalLineAddResultItem()->ID); $this->assertContains($lineNumber, array_column($this->externalLine->get()->getExternalLines(), 'NUMBER')); @@ -52,11 +43,16 @@ public function testGetExternalLine(): void $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 = (string)time(); + $lineNumber = (string)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')); From d822d5b7247ba3b72deda2d8b9852b59bde81af5 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 15 Jun 2024 17:52:01 +0600 Subject: [PATCH 044/138] Refactor code for improved readability and performance This commit introduces a few changes to clean up and optimize the code. The code for the Telephony services tests has been refactored for improved readability by using class imports instead of fully qualified class names. The Makefile has been updated with more descriptive commands. Additionally, unnecessary type casting in the test for adding and deleting external lines has been removed, providing a slight performance boost. Signed-off-by: mesilov --- Makefile | 2 +- .../Telephony/Call/Service/CallTest.php | 15 +++++++++------ .../ExternalCall/Service/ExternalCallTest.php | 18 ++++++++++-------- .../ExternalLine/Service/ExternalLineTest.php | 4 ++-- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/Makefile b/Makefile index c21aa058..480db6f4 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ default: @echo "make needs target:" @egrep -e '^\S+' ./Makefile | grep -v default | sed -r 's/://' | sed -r 's/^/ - /' -phpstan: +lint-phpstan: vendor/bin/phpstan --memory-limit=1G analyse lint-rector: vendor/bin/rector process --dry-run diff --git a/tests/Integration/Services/Telephony/Call/Service/CallTest.php b/tests/Integration/Services/Telephony/Call/Service/CallTest.php index 9218b388..d8d21038 100644 --- a/tests/Integration/Services/Telephony/Call/Service/CallTest.php +++ b/tests/Integration/Services/Telephony/Call/Service/CallTest.php @@ -7,6 +7,10 @@ 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; @@ -21,12 +25,11 @@ use PHPUnit\Framework\Attributes\TestDox; use PHPUnit\Framework\TestCase; use Random\RandomException; -use Bitrix24\SDK\Services\Telephony; -#[CoversClass(Telephony\Call\Service\Call::class)] +#[CoversClass(Call::class)] class CallTest extends TestCase { - private Telephony\Call\Service\Call $call; + private Call $call; private ExternalCall $externalCall; @@ -57,12 +60,12 @@ public static function callIdDataProvider(): Generator $currentB24UserId, $phoneNumber, CarbonImmutable::now(), - Telephony\Common\CallType::outbound, + CallType::outbound, true, true, '3333', null, - Telephony\Common\CrmEntityType::contact + CrmEntityType::contact ); @@ -89,7 +92,7 @@ public function testFinishWithUserId(string $callId, int $currentB24UserId): voi $currentB24UserId, $duration, $money, - Telephony\Common\TelephonyCallStatusCode::successful, + TelephonyCallStatusCode::successful, true ); diff --git a/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php b/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php index d7ad18eb..d8369eec 100644 --- a/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php +++ b/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php @@ -8,8 +8,10 @@ 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\Services\Telephony; use Bitrix24\SDK\Tests\Integration\Fabric; use Carbon\CarbonImmutable; use Generator; @@ -56,12 +58,12 @@ public static function callIdDataProvider(): Generator $currentB24UserId, $phoneNumber, CarbonImmutable::now(), - Telephony\Common\CallType::outbound, + CallType::outbound, true, true, '3333', null, - Telephony\Common\CrmEntityType::contact + CrmEntityType::contact ); @@ -97,12 +99,12 @@ public function testRegister(): void $currentB24UserId, $phoneNumber, CarbonImmutable::now(), - Telephony\Common\CallType::outbound, + CallType::outbound, true, true, '3333', null, - Telephony\Common\CrmEntityType::contact + CrmEntityType::contact ); @@ -146,7 +148,7 @@ public function testFinishWithUserId(string $callId, int $currentB24UserId): voi $currentB24UserId, $duration, $money, - Telephony\Common\TelephonyCallStatusCode::successful, + TelephonyCallStatusCode::successful, true ); @@ -167,7 +169,7 @@ public function testAttachRecordInBase64(string $callId, int $currentB24UserId): $currentB24UserId, $duration, $money, - Telephony\Common\TelephonyCallStatusCode::successful, + TelephonyCallStatusCode::successful, true ); $filename = dirname(__DIR__,2) . '/call-record-test.mp3'; @@ -187,7 +189,7 @@ public function testGetCallRecordUploadUrl(string $callId, int $currentB24UserId $currentB24UserId, 100, new Money(10000, new Currency('USD')), - Telephony\Common\TelephonyCallStatusCode::successful, + TelephonyCallStatusCode::successful, true ); diff --git a/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php b/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php index 0cfab2bb..8c4fc6af 100644 --- a/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php +++ b/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php @@ -29,7 +29,7 @@ class ExternalLineTest extends TestCase #[TestDox('Method tests add external line method')] public function testExternalLineAdd(): void { - $lineNumber = (string)time() . abs(random_int(PHP_INT_MIN, PHP_INT_MAX)); + $lineNumber = time() . abs(random_int(PHP_INT_MIN, PHP_INT_MAX)); $res = $this->externalLine->add($lineNumber, true, sprintf('line-name-%s', $lineNumber)); $this->assertGreaterThan(0, $res->getExternalLineAddResultItem()->ID); $this->assertContains($lineNumber, array_column($this->externalLine->get()->getExternalLines(), 'NUMBER')); @@ -52,7 +52,7 @@ public function testGetExternalLine(): void #[TestDox('Method tests delete external line method')] public function testDeleteExternalLine(): void { - $lineNumber = (string)time() . abs(random_int(PHP_INT_MIN, PHP_INT_MAX)); + $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')); From 4957cf4c32764974e9536cca47150e795e320cf9 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 15 Jun 2024 18:15:53 +0600 Subject: [PATCH 045/138] Refactor code, removing unnecessary imports and updating variables In this update, multiple unused import statements were removed from several files, enhancing code cleanliness. Additionally, variable names were updated for improved readability. Some syntax changes were made as well, such as revising switch cases to match conditionals for better efficiency. Signed-off-by: mesilov --- rector.php | 12 ++++-- .../Result/TranscriptAttachItemResult.php | 1 - src/Services/Telephony/Call/Service/Call.php | 32 +++++---------- .../CallRecordFileUploadedItemResult.php | 5 --- .../Result/ExternalCallFinishedItemResult.php | 2 +- .../ExternalCallRegisteredItemResult.php | 2 + .../Result/SearchCrmEntitiesItemResult.php | 17 +++----- .../Result/SearchCrmEntitiesResult.php | 1 + .../Result/UserDigestItemResult.php | 2 - .../ExternalCall/Service/ExternalCall.php | 41 ++++++------------- .../Result/ExternalLineAddItemResult.php | 1 - .../Result/ExternalLineItemResult.php | 1 - .../Result/ExternalLinesResult.php | 1 + .../ExternalLine/Service/ExternalLine.php | 21 +--------- 14 files changed, 46 insertions(+), 93 deletions(-) diff --git a/rector.php b/rector.php index ba79510c..43668daa 100644 --- a/rector.php +++ b/rector.php @@ -3,12 +3,13 @@ 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/Services/Workflows', + __DIR__ . '/src/Services/Telephony', __DIR__ . '/tests/Integration/Services/Telephony', ]) ->withCache(cacheDirectory: __DIR__ . '.cache/rector') @@ -20,7 +21,9 @@ ) ->withImportNames( importNames: false, - removeUnusedImports: true + importDocBlockNames: false, + importShortClasses: false, + removeUnusedImports: true, ) ->withPhpSets( php82: true // 8.2 @@ -35,4 +38,7 @@ instanceOf: true, earlyReturn: true, strictBooleans: true - ); \ No newline at end of file + ) + ->withSkip([ + RenamePropertyToMatchTypeRector::class + ]); \ No newline at end of file diff --git a/src/Services/Telephony/Call/Result/TranscriptAttachItemResult.php b/src/Services/Telephony/Call/Result/TranscriptAttachItemResult.php index 580ce0a6..ef5945ba 100644 --- a/src/Services/Telephony/Call/Result/TranscriptAttachItemResult.php +++ b/src/Services/Telephony/Call/Result/TranscriptAttachItemResult.php @@ -5,7 +5,6 @@ namespace Bitrix24\SDK\Services\Telephony\Call\Result; use Bitrix24\SDK\Core\Result\AbstractItem; -use Bitrix24\SDK\Services\Telephony\Common\CrmEntity; /** * @property-read non-negative-int $TRANSCRIPT_ID diff --git a/src/Services/Telephony/Call/Service/Call.php b/src/Services/Telephony/Call/Service/Call.php index eddf68a2..4ffa221e 100644 --- a/src/Services/Telephony/Call/Service/Call.php +++ b/src/Services/Telephony/Call/Service/Call.php @@ -6,20 +6,11 @@ use Bitrix24\SDK\Core\Contracts\CoreInterface; 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\Call\Result\TranscriptAttachedResult; -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\ExternalCall\Result\CallRecordUploadUrlResult; use Bitrix24\SDK\Services\Telephony\Call\Service\Batch; -use Carbon\CarbonImmutable; use Money\Money; use Psr\Log\LoggerInterface; @@ -28,42 +19,41 @@ class Call extends AbstractService public function __construct( readonly public Batch $batch, CoreInterface $core, - LoggerInterface $log + LoggerInterface $logger ) { - parent::__construct($core, $log); + parent::__construct($core, $logger); } /** * The method adds a call transcript. * * @param non-empty-string $callId - * @param Money $cost * @param TranscriptMessage[] $messages - * @return TranscriptAttachedResult * @throws BaseException * @throws TransportException * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_call_attachtranscription.php */ public function attachTranscription( string $callId, - Money $cost, + Money $money, array $messages ): TranscriptAttachedResult { $rawMessages = []; - foreach ($messages as $item) { + foreach ($messages as $message) { $rawMessages[] = [ - 'SIDE' => $item->side->value, - 'START_TIME' => $item->startTime, - 'STOP_TIME' => $item->stopTime, - 'MESSAGE' => $item->message + '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($cost), - 'COST_CURRENCY' => $cost->getCurrency()->getCode(), + 'COST' => $this->decimalMoneyFormatter->format($money), + 'COST_CURRENCY' => $money->getCurrency()->getCode(), 'MESSAGES' => $rawMessages ])); } diff --git a/src/Services/Telephony/ExternalCall/Result/CallRecordFileUploadedItemResult.php b/src/Services/Telephony/ExternalCall/Result/CallRecordFileUploadedItemResult.php index cabaee3f..8abf0d14 100644 --- a/src/Services/Telephony/ExternalCall/Result/CallRecordFileUploadedItemResult.php +++ b/src/Services/Telephony/ExternalCall/Result/CallRecordFileUploadedItemResult.php @@ -5,11 +5,6 @@ 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; -use Money\Parser\DecimalMoneyParser; /** * @property-read int $FILE_ID diff --git a/src/Services/Telephony/ExternalCall/Result/ExternalCallFinishedItemResult.php b/src/Services/Telephony/ExternalCall/Result/ExternalCallFinishedItemResult.php index ff1d0d00..72f4189a 100644 --- a/src/Services/Telephony/ExternalCall/Result/ExternalCallFinishedItemResult.php +++ b/src/Services/Telephony/ExternalCall/Result/ExternalCallFinishedItemResult.php @@ -9,7 +9,6 @@ use Bitrix24\SDK\Services\Telephony\Common\CrmEntityType; use Money\Currency; use Money\Money; -use Money\Parser\DecimalMoneyParser; /** * @property-read string $CALL_ID Call ID inside Bitrix24. @@ -63,6 +62,7 @@ public function __get($offset) CrmEntityType::from($item['ENTITY_TYPE']) ); } + return $res; default: return $this->data[$offset] ?? null; diff --git a/src/Services/Telephony/ExternalCall/Result/ExternalCallRegisteredItemResult.php b/src/Services/Telephony/ExternalCall/Result/ExternalCallRegisteredItemResult.php index 8210c5d9..65deebb8 100644 --- a/src/Services/Telephony/ExternalCall/Result/ExternalCallRegisteredItemResult.php +++ b/src/Services/Telephony/ExternalCall/Result/ExternalCallRegisteredItemResult.php @@ -31,6 +31,7 @@ public function __get($offset) CrmEntityType::from($item['ENTITY_TYPE']) ); } + return $res; default: return $this->data[$offset] ?? null; @@ -42,6 +43,7 @@ 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/SearchCrmEntitiesItemResult.php b/src/Services/Telephony/ExternalCall/Result/SearchCrmEntitiesItemResult.php index 1dac45d2..68401e49 100644 --- a/src/Services/Telephony/ExternalCall/Result/SearchCrmEntitiesItemResult.php +++ b/src/Services/Telephony/ExternalCall/Result/SearchCrmEntitiesItemResult.php @@ -18,16 +18,11 @@ class SearchCrmEntitiesItemResult extends AbstractItem { public function __get($offset) { - switch ($offset) { - case'CRM_ENTITY_TYPE': - return CrmEntityType::from($this->data[$offset]); - case 'CRM_ENTITY_ID': - case 'ASSIGNED_BY_ID': - return (int)$this->data[$offset]; - case 'ASSIGNED_BY': - return new UserDigestItemResult($this->data[$offset]); - default: - return $this->data[$offset] ?? null; - } + 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 index bd6bc1e9..db2f1df5 100644 --- a/src/Services/Telephony/ExternalCall/Result/SearchCrmEntitiesResult.php +++ b/src/Services/Telephony/ExternalCall/Result/SearchCrmEntitiesResult.php @@ -19,6 +19,7 @@ public function getCrmEntities(): array 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 index 8eb876c2..62585ca6 100644 --- a/src/Services/Telephony/ExternalCall/Result/UserDigestItemResult.php +++ b/src/Services/Telephony/ExternalCall/Result/UserDigestItemResult.php @@ -5,8 +5,6 @@ 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 int $ID diff --git a/src/Services/Telephony/ExternalCall/Service/ExternalCall.php b/src/Services/Telephony/ExternalCall/Service/ExternalCall.php index 62ef17b6..64dedbfe 100644 --- a/src/Services/Telephony/ExternalCall/Service/ExternalCall.php +++ b/src/Services/Telephony/ExternalCall/Service/ExternalCall.php @@ -30,10 +30,10 @@ public function __construct( readonly public Batch $batch, private readonly Base64Encoder $base64Encoder, CoreInterface $core, - LoggerInterface $log + LoggerInterface $logger ) { - parent::__construct($core, $log); + parent::__construct($core, $logger); } /** @@ -41,7 +41,6 @@ public function __construct( * * @param non-empty-string $callId * @param non-empty-string $callRecordFileName - * @return CallRecordUploadUrlResult * @throws BaseException * @throws InvalidArgumentException * @throws TransportException @@ -65,7 +64,6 @@ public function getCallRecordUploadUrl( * * @param non-empty-string $callId * @param non-empty-string $callRecordFileName - * @return CallRecordFileUploadedResult * @throws BaseException * @throws InvalidArgumentException * @throws TransportException @@ -123,7 +121,6 @@ public function attachCallRecordInBase64( * @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. - * @return ExternalCallRegisteredResult * @throws BaseException * @throws TransportException * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_register.php @@ -150,7 +147,7 @@ public function register( 'USER_ID' => $b24UserId, 'PHONE_NUMBER' => $phoneNumber, 'CALL_START_DATE' => $callStartDate->format(DATE_ATOM), - 'CRM_CREATE' => $isCreateCrmEntities ? 1 : 0, + 'CRM_CREATE' => $isCreateCrmEntities === true ? 1 : 0, 'CRM_SOURCE' => $sourceId, 'CRM_ENTITY_TYPE' => $crmEntityType?->value, 'CRM_ENTITY_ID' => $crmEntityId, @@ -201,12 +198,7 @@ public function searchCrmEntities(string $phoneNumber): SearchCrmEntitiesResult * @param non-empty-string $callId * @param non-empty-string $userInnerPhoneNumber * @param non-negative-int $duration - * @param Money $callCost - * @param TelephonyCallStatusCode $callStatus - * @param bool $isAddCallToChat * @param non-empty-string|null $failedReason - * @param int|null $userVote - * @return ExternalCallFinishedResult * @throws BaseException * @throws TransportException * @see https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_finish.php @@ -215,8 +207,8 @@ public function finishForUserPhoneInner( string $callId, string $userInnerPhoneNumber, int $duration, - Money $callCost, - TelephonyCallStatusCode $callStatus, + Money $money, + TelephonyCallStatusCode $telephonyCallStatusCode, bool $isAddCallToChat = false, ?string $failedReason = null, ?int $userVote = null, @@ -227,9 +219,9 @@ public function finishForUserPhoneInner( 'CALL_ID' => $callId, 'USER_ID' => $userInnerPhoneNumber, 'DURATION' => $duration, - 'COST' => $this->decimalMoneyFormatter->format($callCost), - 'COST_CURRENCY' => $callCost->getCurrency()->getCode(), - 'STATUS_CODE' => $callStatus->value, + '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 @@ -242,12 +234,7 @@ public function finishForUserPhoneInner( * @param non-empty-string $callId * @param positive-int $b24UserId * @param non-negative-int $duration - * @param Money $callCost - * @param TelephonyCallStatusCode $callStatus - * @param bool $isAddCallToChat * @param non-empty-string|null $failedReason - * @param int|null $userVote - * @return ExternalCallFinishedResult * @throws BaseException * @throws TransportException * @see https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_finish.php @@ -256,8 +243,8 @@ public function finishForUserId( string $callId, int $b24UserId, int $duration, - Money $callCost, - TelephonyCallStatusCode $callStatus, + Money $money, + TelephonyCallStatusCode $telephonyCallStatusCode, bool $isAddCallToChat = false, ?string $failedReason = null, ?int $userVote = null, @@ -268,9 +255,9 @@ public function finishForUserId( 'CALL_ID' => $callId, 'USER_ID' => $b24UserId, 'DURATION' => $duration, - 'COST' => $this->decimalMoneyFormatter->format($callCost), - 'COST_CURRENCY' => $callCost->getCurrency()->getCode(), - 'STATUS_CODE' => $callStatus->value, + '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 @@ -282,7 +269,6 @@ public function finishForUserId( * * @param non-empty-string $callId * @param array $b24UserId - * @return UserInterfaceDialogCallResult * @throws BaseException * @throws TransportException * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_show.php @@ -301,7 +287,6 @@ public function show(string $callId, array $b24UserId): UserInterfaceDialogCallR * * @param non-empty-string $callId * @param array $b24UserId - * @return UserInterfaceDialogCallResult * @throws BaseException * @throws TransportException * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalcall_hide.php diff --git a/src/Services/Telephony/ExternalLine/Result/ExternalLineAddItemResult.php b/src/Services/Telephony/ExternalLine/Result/ExternalLineAddItemResult.php index 2dbd4cf6..87cbbf75 100644 --- a/src/Services/Telephony/ExternalLine/Result/ExternalLineAddItemResult.php +++ b/src/Services/Telephony/ExternalLine/Result/ExternalLineAddItemResult.php @@ -5,7 +5,6 @@ namespace Bitrix24\SDK\Services\Telephony\ExternalLine\Result; use Bitrix24\SDK\Core\Result\AbstractItem; -use Bitrix24\SDK\Services\Telephony\Common\CrmEntity; /** * @property-read non-negative-int $ID diff --git a/src/Services/Telephony/ExternalLine/Result/ExternalLineItemResult.php b/src/Services/Telephony/ExternalLine/Result/ExternalLineItemResult.php index 8fd4109e..ae13aa3d 100644 --- a/src/Services/Telephony/ExternalLine/Result/ExternalLineItemResult.php +++ b/src/Services/Telephony/ExternalLine/Result/ExternalLineItemResult.php @@ -5,7 +5,6 @@ namespace Bitrix24\SDK\Services\Telephony\ExternalLine\Result; use Bitrix24\SDK\Core\Result\AbstractItem; -use Bitrix24\SDK\Services\Telephony\Common\CrmEntity; /** * @property-read non-empty-string $NUMBER diff --git a/src/Services/Telephony/ExternalLine/Result/ExternalLinesResult.php b/src/Services/Telephony/ExternalLine/Result/ExternalLinesResult.php index 7df1f728..97599289 100644 --- a/src/Services/Telephony/ExternalLine/Result/ExternalLinesResult.php +++ b/src/Services/Telephony/ExternalLine/Result/ExternalLinesResult.php @@ -14,6 +14,7 @@ public function getExternalLines(): array 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/ExternalLine.php b/src/Services/Telephony/ExternalLine/Service/ExternalLine.php index 295012ee..969aaa92 100644 --- a/src/Services/Telephony/ExternalLine/Service/ExternalLine.php +++ b/src/Services/Telephony/ExternalLine/Service/ExternalLine.php @@ -6,27 +6,12 @@ use Bitrix24\SDK\Core\Contracts\CoreInterface; 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\AbstractResult; use Bitrix24\SDK\Core\Result\EmptyResult; -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 Bitrix24\SDK\Services\Telephony\ExternalLine\Result\ExternalLineAddedResult; use Bitrix24\SDK\Services\Telephony\ExternalLine\Result\ExternalLinesResult; use Bitrix24\SDK\Services\Telephony\ExternalLine\Service\Batch; -use Carbon\CarbonImmutable; -use Money\Money; use Psr\Log\LoggerInterface; class ExternalLine extends AbstractService @@ -34,10 +19,10 @@ class ExternalLine extends AbstractService public function __construct( readonly public Batch $batch, CoreInterface $core, - LoggerInterface $log + LoggerInterface $logger ) { - parent::__construct($core, $log); + parent::__construct($core, $logger); } /** @@ -63,8 +48,6 @@ public function add(string $lineNumber, bool $isAutoCreateCrmEntities = true, ?s /** * Method for deleting an external line. * - * @param string $lineNumber - * @return EmptyResult * @throws BaseException * @throws TransportException * @link https://training.bitrix24.com/rest_help/scope_telephony/telephony/telephony_externalLine_delete.php From 9367dfb1ccbce97b6b60a9d4bddac782f924c953 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 15 Jun 2024 18:18:20 +0600 Subject: [PATCH 046/138] Disable removal of unused imports in rector.php The configuration for the Rector has been updated to stop the removal of unused imports. This change ensures that all imports, whether used or not, are retained in the code. Signed-off-by: mesilov --- rector.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rector.php b/rector.php index 43668daa..85ed9bf9 100644 --- a/rector.php +++ b/rector.php @@ -23,7 +23,7 @@ importNames: false, importDocBlockNames: false, importShortClasses: false, - removeUnusedImports: true, + removeUnusedImports: false, ) ->withPhpSets( php82: true // 8.2 From 34a99b87bfac0f03eb5ba046337e43785ece1528 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 15 Jun 2024 19:30:14 +0600 Subject: [PATCH 047/138] Add Voximplant SIP support in telephony services This code update introduces support for SIP lines in the Voximplant namespace. SIP support includes methods to get a list of SIP lines, add a new SIP line, and delete a SIP line. This enhancement in the telephony service makes the overall application more equipped for handling voice services. Signed-off-by: mesilov --- CHANGELOG.md | 14 ++- src/Services/Telephony/Common/PbxType.php | 11 +++ .../Telephony/TelephonyServiceBuilder.php | 14 +++ .../Sip/Result/SipLineAddedResult.php | 16 ++++ .../Sip/Result/SipLineItemResult.php | 40 +++++++++ .../Voximplant/Sip/Result/SipLinesResult.php | 26 ++++++ .../Voximplant/Sip/Service/Batch.php | 17 ++++ .../Telephony/Voximplant/Sip/Service/Sip.php | 83 +++++++++++++++++ .../Voximplant/VoximplantServiceBuilder.php | 26 ++++++ .../Telephony/Voximplant/Sip/SipTest.php | 88 +++++++++++++++++++ 10 files changed, 331 insertions(+), 4 deletions(-) create mode 100644 src/Services/Telephony/Common/PbxType.php create mode 100644 src/Services/Telephony/Voximplant/Sip/Result/SipLineAddedResult.php create mode 100644 src/Services/Telephony/Voximplant/Sip/Result/SipLineItemResult.php create mode 100644 src/Services/Telephony/Voximplant/Sip/Result/SipLinesResult.php create mode 100644 src/Services/Telephony/Voximplant/Sip/Service/Batch.php create mode 100644 src/Services/Telephony/Voximplant/Sip/Service/Sip.php create mode 100644 src/Services/Telephony/Voximplant/VoximplantServiceBuilder.php create mode 100644 tests/Integration/Services/Telephony/Voximplant/Sip/SipTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 0436688f..09edf883 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,14 +62,20 @@ * `hide` – hides call information window * `Call` – work with call: * `attachTranscription` – method adds a call transcript - * `Call` – work with external line: - * `add` – method adds an external line - * `delete` – method delete external line - * `get` – method gets external lines list + * `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 * 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 ## 2.0-beta.2 — 1.04.2024 diff --git a/src/Services/Telephony/Common/PbxType.php b/src/Services/Telephony/Common/PbxType.php new file mode 100644 index 00000000..e6e07e81 --- /dev/null +++ b/src/Services/Telephony/Common/PbxType.php @@ -0,0 +1,11 @@ +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/Sip/Result/SipLineAddedResult.php b/src/Services/Telephony/Voximplant/Sip/Result/SipLineAddedResult.php new file mode 100644 index 00000000..2701cb83 --- /dev/null +++ b/src/Services/Telephony/Voximplant/Sip/Result/SipLineAddedResult.php @@ -0,0 +1,16 @@ +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..117e3e41 --- /dev/null +++ b/src/Services/Telephony/Voximplant/Sip/Result/SipLineItemResult.php @@ -0,0 +1,40 @@ + (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/SipLinesResult.php b/src/Services/Telephony/Voximplant/Sip/Result/SipLinesResult.php new file mode 100644 index 00000000..4ff7bfce --- /dev/null +++ b/src/Services/Telephony/Voximplant/Sip/Result/SipLinesResult.php @@ -0,0 +1,26 @@ +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..2a458e34 --- /dev/null +++ b/src/Services/Telephony/Voximplant/Sip/Service/Batch.php @@ -0,0 +1,17 @@ +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 + */ + 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 + */ + public function get(): SipLinesResult + { + return new SipLinesResult($this->core->call('voximplant.sip.get')); + } +} \ 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..d1466324 --- /dev/null +++ b/src/Services/Telephony/Voximplant/VoximplantServiceBuilder.php @@ -0,0 +1,26 @@ +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__]; + } +} \ 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..c0a0d0e4 --- /dev/null +++ b/tests/Integration/Services/Telephony/Voximplant/Sip/SipTest.php @@ -0,0 +1,88 @@ +assertGreaterThan(0, count($this->sip->get()->getLines())); + } + + public function testDelete(): void + { + $sipTitle = 'test sip - ' . Uuid::v4()->toRfc4122(); + $serverUrl = 'supersip.io'; + $login = Uuid::v4()->toRfc4122(); + $password = Uuid::v4()->toRfc4122(); + + $addedLine = $this->sip->add( + PbxType::cloud, + $sipTitle, + $serverUrl, + $login, + $password + ); + $this->assertTrue(in_array($addedLine->getLine()->CONFIG_ID, array_column($this->sip->get()->getLines(), 'CONFIG_ID'))); + + $this->assertTrue($this->sip->delete($addedLine->getLine()->CONFIG_ID)->isSuccess()); + + $this->assertFalse(in_array($addedLine->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(); + + $addedLine = $this->sip->add( + PbxType::cloud, + $sipTitle, + $serverUrl, + $login, + $password + ); + $this->assertEquals($sipTitle, $addedLine->getLine()->TITLE); + $this->assertEquals($serverUrl, $addedLine->getLine()->SERVER); + $this->assertEquals($login, $addedLine->getLine()->LOGIN); + $this->assertEquals($password, $addedLine->getLine()->PASSWORD); + + $this->sip->delete($addedLine->getLine()->CONFIG_ID)->isSuccess(); + } + + protected function setUp(): void + { + $this->sip = Fabric::getServiceBuilder()->getTelephonyScope()->getVoximplantServiceBuilder()->sip(); + } +} \ No newline at end of file From 268e0af90ed3e5cc7d7440addc8d250e4023d18c Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 15 Jun 2024 19:58:34 +0600 Subject: [PATCH 048/138] Add SIP registration status functionality Introduced a new status function for SIP registration mainly for cloud hosted PBX. This includes the creation of relevant new classes such as `SipLineStatusItemResult`, `SipLineStatusResult`, and `SipRegistrationStatus`. Updated the `CHANGELOG.md` to reflect these changes. Signed-off-by: mesilov --- CHANGELOG.md | 2 ++ .../Common/SipRegistrationStatus.php | 13 +++++++ .../Sip/Result/SipLineStatusItemResult.php | 34 +++++++++++++++++++ .../Sip/Result/SipLineStatusResult.php | 16 +++++++++ .../Telephony/Voximplant/Sip/Service/Sip.php | 19 +++++++++++ 5 files changed, 84 insertions(+) create mode 100644 src/Services/Telephony/Common/SipRegistrationStatus.php create mode 100644 src/Services/Telephony/Voximplant/Sip/Result/SipLineStatusItemResult.php create mode 100644 src/Services/Telephony/Voximplant/Sip/Result/SipLineStatusResult.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 09edf883..6a5afba0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -71,11 +71,13 @@ * `get` - get sip lines list * `add` - add new sip line * `delete` - delete sip line + * `status` - pbx sip line registration status * 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 ## 2.0-beta.2 — 1.04.2024 diff --git a/src/Services/Telephony/Common/SipRegistrationStatus.php b/src/Services/Telephony/Common/SipRegistrationStatus.php new file mode 100644 index 00000000..234475da --- /dev/null +++ b/src/Services/Telephony/Common/SipRegistrationStatus.php @@ -0,0 +1,13 @@ + (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..3fd1dab0 --- /dev/null +++ b/src/Services/Telephony/Voximplant/Sip/Result/SipLineStatusResult.php @@ -0,0 +1,16 @@ +getCoreResponse()->getResponseData()->getResult()); + } +} \ 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 index 17a0f1f0..ea25c927 100644 --- a/src/Services/Telephony/Voximplant/Sip/Service/Sip.php +++ b/src/Services/Telephony/Voximplant/Sip/Service/Sip.php @@ -15,6 +15,8 @@ use Bitrix24\SDK\Services\Telephony\ExternalLine\Result\ExternalLinesResult; 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\SipLineStatusItemResult; +use Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result\SipLineStatusResult; use Psr\Log\LoggerInterface; class Sip extends AbstractService @@ -80,4 +82,21 @@ 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 + */ + public function status(int $sipRegistrationId): SipLineStatusResult + { + return new SipLineStatusResult($this->core->call('voximplant.sip.status', [ + 'REG_ID' => $sipRegistrationId + ])); + } } \ No newline at end of file From e1cb1e05ecd44963afb7ff86d2de75fe62144486 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 15 Jun 2024 19:58:58 +0600 Subject: [PATCH 049/138] Update SIP tests with new functionalities Enhanced SIP tests in the SipTest.php by adding test assertions for add and delete line methods, as well as get line status method. The 'tearDown' method was updated to delete all cloud PBX lines after each test to ensure a clean testing environment. Signed-off-by: mesilov --- .../Telephony/Voximplant/Sip/SipTest.php | 53 ++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/tests/Integration/Services/Telephony/Voximplant/Sip/SipTest.php b/tests/Integration/Services/Telephony/Voximplant/Sip/SipTest.php index c0a0d0e4..f12f3e13 100644 --- a/tests/Integration/Services/Telephony/Voximplant/Sip/SipTest.php +++ b/tests/Integration/Services/Telephony/Voximplant/Sip/SipTest.php @@ -29,9 +29,24 @@ class SipTest extends TestCase #[TestDox('Method tests sip get method')] public function testGet(): void { - $this->assertGreaterThan(0, count($this->sip->get()->getLines())); + $sipTitle = 'test sip - ' . Uuid::v4()->toRfc4122(); + $serverUrl = 'supersip.io'; + $login = Uuid::v4()->toRfc4122(); + $password = Uuid::v4()->toRfc4122(); + + $addedLine = $this->sip->add( + PbxType::cloud, + $sipTitle, + $serverUrl, + $login, + $password + ); + $this->assertGreaterThanOrEqual(1, count($this->sip->get()->getLines())); + $this->assertTrue($this->sip->delete($addedLine->getLine()->CONFIG_ID)->isSuccess()); } + #[Test] + #[TestDox('Method tests sip delete line method')] public function testDelete(): void { $sipTitle = 'test sip - ' . Uuid::v4()->toRfc4122(); @@ -81,6 +96,42 @@ public function testAdd(): void $this->sip->delete($addedLine->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(); + + $addedLine = $this->sip->add( + PbxType::cloud, + $sipTitle, + $serverUrl, + $login, + $password + ); + + $sipLineStatus = $this->sip->status($addedLine->getLine()->REG_ID)->getStatus(); + $this->assertEquals($addedLine->getLine()->REG_ID, $sipLineStatus->REG_ID); + + $this->sip->delete($addedLine->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(); From 5b4abb31d02a673186ac31ec4c7e1ecdb056a222 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 15 Jun 2024 20:35:35 +0600 Subject: [PATCH 050/138] Add SIP line update function and tests The code now includes a new method for updating SIP line settings in the Voximplant Sip Service. Functionality for this method is supported by validation checks and relevant exceptions. A corresponding unit test to confirm the behavior of the update functionality has also been added. Signed-off-by: mesilov --- CHANGELOG.md | 1 + .../Telephony/Voximplant/Sip/Service/Sip.php | 47 +++++++++++++++++++ .../Telephony/Voximplant/Sip/SipTest.php | 28 +++++++++++ 3 files changed, 76 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a5afba0..e22e05ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -72,6 +72,7 @@ * `add` - add new sip line * `delete` - delete sip line * `status` - pbx sip line registration status + * `update` - update sip line settings * add `TranscriptMessage` – data structure for transcript message item * add `TranscriptMessageSide` – enum for describe side of diarization * add `CallType` – call types enum diff --git a/src/Services/Telephony/Voximplant/Sip/Service/Sip.php b/src/Services/Telephony/Voximplant/Sip/Service/Sip.php index ea25c927..66966af1 100644 --- a/src/Services/Telephony/Voximplant/Sip/Service/Sip.php +++ b/src/Services/Telephony/Voximplant/Sip/Service/Sip.php @@ -6,9 +6,11 @@ use Bitrix24\SDK\Core\Contracts\CoreInterface; 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\EmptyResult; +use Bitrix24\SDK\Core\Result\UpdatedItemResult; use Bitrix24\SDK\Services\AbstractService; use Bitrix24\SDK\Services\Telephony\Common\PbxType; use Bitrix24\SDK\Services\Telephony\ExternalLine\Result\ExternalLineAddedResult; @@ -99,4 +101,49 @@ public function status(int $sipRegistrationId): SipLineStatusResult '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 + */ + 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/tests/Integration/Services/Telephony/Voximplant/Sip/SipTest.php b/tests/Integration/Services/Telephony/Voximplant/Sip/SipTest.php index f12f3e13..1291c748 100644 --- a/tests/Integration/Services/Telephony/Voximplant/Sip/SipTest.php +++ b/tests/Integration/Services/Telephony/Voximplant/Sip/SipTest.php @@ -96,6 +96,34 @@ public function testAdd(): void $this->sip->delete($addedLine->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(); + + $addedLine = $this->sip->add( + PbxType::cloud, + $sipTitle, + $serverUrl, + $login, + $password + ); + + $newTitle = 'test sip updated title - ' . Uuid::v4()->toRfc4122(); + $this->assertTrue($this->sip->update( + $addedLine->getLine()->CONFIG_ID, + $addedLine->getLine()->TYPE, + $newTitle + )->isSuccess()); + + + $this->sip->delete($addedLine->getLine()->CONFIG_ID)->isSuccess(); + } + #[Test] #[TestDox('Method tests sip get line status method')] public function testStatus(): void From 0a12b52d757a19c669d4b5d1a358daf77f97589f Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 19 Jun 2024 23:06:55 +0600 Subject: [PATCH 051/138] Add webhook context check and update test cases The Credentials.php file is updated with a method 'isWebhookContext' that checks the current context initialization. The CredentialsTest.php and phpstan.neon.dist files were also modified to incorporate new tests and directories. The files related to documentation have been updated accordingly. Signed-off-by: mesilov --- CHANGELOG.md | 34 +++++++------ phpstan.neon.dist | 1 + src/Core/Credentials/Credentials.php | 41 ++++++++-------- .../Unit/Core/Credentials/CredentialsTest.php | 48 ++++++++++++------- 4 files changed, 73 insertions(+), 51 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e22e05ac..b06502e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,13 +40,15 @@ * `list` – List of workflow tasks * add `WorkflowActivityDocumentType` * add method `Bitrix24\SDK\Core\Credentials\AccessToken::initFromWorkflowRequest` -* 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\Result\UserInterfaceDialogCallResult` result of call UI +* 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\Result\UserInterfaceDialogCallResult` result of call UI * add `IncomingRobotRequest` wrapper for data from crm-robot request * add `IncomingWorkflowRequest` wrapper for data from biz proc activity request * add [Rector](https://github.com/rectorphp/rector) for improve code quality and speed up releases cycle * add `Bitrix24\SDK\Core\Exceptions\UserNotFoundOrIsNotActiveException` exception if user not found, or it is not active +* add `Bitrix24\SDK\Core\Credentials::isWebhookContext` - for check is current context init from webhook ### Changed @@ -56,29 +58,31 @@ * `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 + * `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: + * `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 + * `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 + * `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 * 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 + * add `SipRegistrationStatus` – pbx sip line registration status ## 2.0-beta.2 — 1.04.2024 diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 337e4f57..06170dda 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -2,6 +2,7 @@ parameters: level: 5 paths: - src/ + - tests/Integration/Services/Telephony bootstrapFiles: - tests/bootstrap.php parallel: diff --git a/src/Core/Credentials/Credentials.php b/src/Core/Credentials/Credentials.php index 54260ac6..476bfc38 100644 --- a/src/Core/Credentials/Credentials.php +++ b/src/Core/Credentials/Credentials.php @@ -7,11 +7,6 @@ use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; use Bitrix24\SDK\Application\Requests\Placement\PlacementRequest; -/** - * Class Credentials - * - * @package Bitrix24\SDK\Core\Credentials - */ class Credentials { protected ?WebhookUrl $webhookUrl; @@ -22,19 +17,20 @@ class Credentials /** * Credentials constructor. * - * @param WebhookUrl|null $webhookUrl - * @param AccessToken|null $accessToken + * @param WebhookUrl|null $webhookUrl + * @param AccessToken|null $accessToken * @param ApplicationProfile|null $applicationProfile - * @param string|null $domainUrl + * @param string|null $domainUrl * - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws InvalidArgumentException */ public function __construct( - ?WebhookUrl $webhookUrl, - ?AccessToken $accessToken, + ?WebhookUrl $webhookUrl, + ?AccessToken $accessToken, ?ApplicationProfile $applicationProfile, - ?string $domainUrl - ) { + ?string $domainUrl + ) + { $this->webhookUrl = $webhookUrl; $this->accessToken = $accessToken; $this->applicationProfile = $applicationProfile; @@ -65,7 +61,7 @@ public function setAccessToken(AccessToken $accessToken): void * @param string $domainUrl * * @return void - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws InvalidArgumentException */ public function setDomainUrl(string $domainUrl): void { @@ -80,6 +76,11 @@ public function setDomainUrl(string $domainUrl): void $this->domainUrl = $domainUrl; } + public function isWebhookContext(): bool + { + return $this->webhookUrl !== null && $this->accessToken === null; + } + /** * @return ApplicationProfile|null */ @@ -122,7 +123,7 @@ public function getAccessToken(): ?AccessToken * @param WebhookUrl $webhookUrl * * @return self - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws InvalidArgumentException */ public static function createFromWebhook(WebhookUrl $webhookUrl): self { @@ -135,12 +136,12 @@ public static function createFromWebhook(WebhookUrl $webhookUrl): self } /** - * @param AccessToken $accessToken + * @param AccessToken $accessToken * @param ApplicationProfile $applicationProfile - * @param string $domainUrl + * @param string $domainUrl * * @return self - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws InvalidArgumentException */ public static function createFromOAuth(AccessToken $accessToken, ApplicationProfile $applicationProfile, string $domainUrl): self { @@ -154,10 +155,10 @@ public static function createFromOAuth(AccessToken $accessToken, ApplicationProf /** * @param \Bitrix24\SDK\Application\Requests\Placement\PlacementRequest $placementRequest - * @param \Bitrix24\SDK\Core\Credentials\ApplicationProfile $applicationProfile + * @param \Bitrix24\SDK\Core\Credentials\ApplicationProfile $applicationProfile * * @return self - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws InvalidArgumentException */ public static function createFromPlacementRequest(PlacementRequest $placementRequest, ApplicationProfile $applicationProfile): self { diff --git a/tests/Unit/Core/Credentials/CredentialsTest.php b/tests/Unit/Core/Credentials/CredentialsTest.php index 64438eef..65b4ab94 100644 --- a/tests/Unit/Core/Credentials/CredentialsTest.php +++ b/tests/Unit/Core/Credentials/CredentialsTest.php @@ -9,19 +9,20 @@ 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 { - /** - * @dataProvider credentialsDataProviderWithDomainUrlVariants - * - * @param \Bitrix24\SDK\Core\Credentials\Credentials $credentials - * @param $expectedDomainUrl - * - * @return void - */ + #[Test] + #[TestDox('tests get domain url')] + #[DataProvider('credentialsDataProviderWithDomainUrlVariants')] public function testGetDomainUrl( Credentials $credentials, $expectedDomainUrl @@ -31,9 +32,11 @@ public function testGetDomainUrl( /** * @return void - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException - * @throws \Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException + * @throws InvalidArgumentException + * @throws UnknownScopeCodeException */ + #[Test] + #[TestDox('tests get domain url without protocol')] public function testDomainUrlWithoutProtocol(): void { $credentials = Credentials::createFromOAuth( @@ -46,12 +49,25 @@ public function testDomainUrlWithoutProtocol(): void $credentials->getDomainUrl() ); } + #[Test] + #[TestDox('tests isWebhookContext')] + public function testIsWebhookContext():void + { + $credentials = Credentials::createFromOAuth( + new AccessToken('', '', 0), + new ApplicationProfile('', '', new Scope(['crm'])), + 'bitrix24-php-sdk-playground.bitrix24.ru' + ); + $this->assertFalse($credentials->isWebhookContext()); + } /** * @return void - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException - * @throws \Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException + * @throws InvalidArgumentException + * @throws UnknownScopeCodeException */ + #[Test] + #[TestDox('tests domain url with protocol')] public function testDomainUrlWithProtocol(): void { $credentials = Credentials::createFromOAuth( @@ -66,9 +82,9 @@ public function testDomainUrlWithProtocol(): void } /** - * @return \Generator - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException - * @throws \Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException + * @return Generator + * @throws InvalidArgumentException + * @throws UnknownScopeCodeException */ public static function credentialsDataProviderWithDomainUrlVariants(): Generator { From 01c1f4f3f8a4bb2a7b4ed68a945383719686ef9d Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 19 Jun 2024 23:09:18 +0600 Subject: [PATCH 052/138] Add MethodConfirmWaitingException and improve error handling A new exception class, MethodConfirmWaitingException, has been added specifically for handling cases where the `method_confirm_waiting` error occurs. This helps improve granularity in handling different types of errors. The error reporting logic in the Core.php file has been updated to use a switch case structure instead of if conditions, to better manage different error types. Signed-off-by: mesilov --- src/Core/ApiClient.php | 3 + src/Core/Core.php | 59 +++++++++++-------- .../MethodConfirmWaitingException.php | 18 ++++++ 3 files changed, 54 insertions(+), 26 deletions(-) create mode 100644 src/Core/Exceptions/MethodConfirmWaitingException.php diff --git a/src/Core/ApiClient.php b/src/Core/ApiClient.php index 821c1172..4bddc374 100644 --- a/src/Core/ApiClient.php +++ b/src/Core/ApiClient.php @@ -133,6 +133,9 @@ public function getNewAccessToken(): RenewedAccessToken return $newAccessToken; } if ($response->getStatusCode() === StatusCodeInterface::STATUS_BAD_REQUEST) { + $this->logger->warning('getNewAccessToken.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()); diff --git a/src/Core/Core.php b/src/Core/Core.php index 1966c773..a1a473f9 100644 --- a/src/Core/Core.php +++ b/src/Core/Core.php @@ -9,6 +9,7 @@ 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; @@ -127,34 +128,40 @@ public function call(string $apiMethod, array $parameters = []): Response ] ); - if ($body['error'] === 'expired_token') { - // renew access token - $renewedToken = $this->apiClient->getNewAccessToken(); - $this->logger->debug( - 'access token renewed', - [ - 'newAccessToken' => $renewedToken->getAccessToken()->getAccessToken(), - 'newRefreshToken' => $renewedToken->getAccessToken()->getRefreshToken(), - 'newExpires' => $renewedToken->getAccessToken()->getExpires(), - 'appStatus' => $renewedToken->getApplicationStatus(), - ] - ); - $this->apiClient->getCredentials()->setAccessToken($renewedToken->getAccessToken()); + switch (strtolower((string)$body['error'])) { + case 'expired_token': + // renew access token + $renewedToken = $this->apiClient->getNewAccessToken(); + $this->logger->debug( + 'access token renewed', + [ + 'newAccessToken' => $renewedToken->getAccessToken()->getAccessToken(), + 'newRefreshToken' => $renewedToken->getAccessToken()->getRefreshToken(), + 'newExpires' => $renewedToken->getAccessToken()->getExpires(), + 'appStatus' => $renewedToken->getApplicationStatus(), + ] + ); + $this->apiClient->getCredentials()->setAccessToken($renewedToken->getAccessToken()); - // repeat api-call - $response = $this->call($apiMethod, $parameters); - $this->logger->debug( - 'api call repeated', - [ - 'repeatedApiMethod' => $apiMethod, - 'httpStatusCode' => $response->getHttpResponse()->getStatusCode(), - ] - ); + // 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)); - } else { - throw new BaseException('UNAUTHORIZED request error'); + // 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: diff --git a/src/Core/Exceptions/MethodConfirmWaitingException.php b/src/Core/Exceptions/MethodConfirmWaitingException.php new file mode 100644 index 00000000..2b282151 --- /dev/null +++ b/src/Core/Exceptions/MethodConfirmWaitingException.php @@ -0,0 +1,18 @@ +methodName = $methodName; + } +} \ No newline at end of file From 81a12f2536062d952dfcee22f46edc17d5226354 Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 19 Jun 2024 23:15:00 +0600 Subject: [PATCH 053/138] Add User setting methods for Voximplant SIP Added methods to deactivate, activate and get the user settings for the Voximplant SIP service. Included additional classes and files for better organization. These additions help manage SIP-phone availability per user and retrieve user settings effectively. Signed-off-by: mesilov --- CHANGELOG.md | 6 +- .../VoximplantUserSettingsItemResult.php | 28 ++++++ .../Result/VoximplantUserSettingsResult.php | 25 ++++++ .../Voximplant/User/Service/Batch.php | 17 ++++ .../Voximplant/User/Service/User.php | 87 +++++++++++++++++++ .../Voximplant/VoximplantServiceBuilder.php | 13 +++ .../Telephony/Voximplant/User/UserTest.php | 73 ++++++++++++++++ 7 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 src/Services/Telephony/Voximplant/User/Result/VoximplantUserSettingsItemResult.php create mode 100644 src/Services/Telephony/Voximplant/User/Result/VoximplantUserSettingsResult.php create mode 100644 src/Services/Telephony/Voximplant/User/Service/Batch.php create mode 100644 src/Services/Telephony/Voximplant/User/Service/User.php create mode 100644 tests/Integration/Services/Telephony/Voximplant/User/UserTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index b06502e8..f9ab53a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # bitrix24-php-sdk change log -## 2.0-beta.3 — 1.05.2024 +## 2.0-beta.3 — 1.07.2024 ### Added @@ -77,6 +77,10 @@ * `delete` - delete sip line * `status` - pbx sip line registration status * `update` - update sip line settings + * `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 * add `TranscriptMessage` – data structure for transcript message item * add `TranscriptMessageSide` – enum for describe side of diarization * add `CallType` – call types enum 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..fa7007a0 --- /dev/null +++ b/src/Services/Telephony/Voximplant/User/Result/VoximplantUserSettingsItemResult.php @@ -0,0 +1,28 @@ + (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..f5eeaa8e --- /dev/null +++ b/src/Services/Telephony/Voximplant/User/Result/VoximplantUserSettingsResult.php @@ -0,0 +1,25 @@ +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..aab41d26 --- /dev/null +++ b/src/Services/Telephony/Voximplant/User/Service/Batch.php @@ -0,0 +1,17 @@ +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 + */ + 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 + */ + 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 index d1466324..69f86012 100644 --- a/src/Services/Telephony/Voximplant/VoximplantServiceBuilder.php +++ b/src/Services/Telephony/Voximplant/VoximplantServiceBuilder.php @@ -23,4 +23,17 @@ public function sip(): Telephony\Voximplant\Sip\Service\Sip 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__]; + } } \ 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..0b1f9540 --- /dev/null +++ b/tests/Integration/Services/Telephony/Voximplant/User/UserTest.php @@ -0,0 +1,73 @@ +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 From fa4c12a98b206f9d367f7575994fdeb3960e6f88 Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 19 Jun 2024 23:42:27 +0600 Subject: [PATCH 054/138] Add AccessTokenRepositoryInterface with implementation and integration tests Added AccessTokenRepositoryInterface to handle access token operations and its implementation, AccessTokenFileStorage. The provided interface and implementation allows managing access tokens, checking their availability, and saving new tokens. Also, setup for integration tests has been modified to support these changes. Signed-off-by: mesilov --- .gitignore | 1 + tests/ApplicationBridge/.env | 9 +++ .../AccessTokenFileStorage.php | 61 +++++++++++++++++++ .../AccessTokenRepositoryInterface.php | 20 ++++++ .../ApplicationCredentialsProvider.php | 56 +++++++++++++++++ tests/ApplicationBridge/index.php | 57 +++++++++++++++++ tests/ApplicationBridge/install.php | 4 ++ tests/Integration/Fabric.php | 55 ++++++++++++++--- 8 files changed, 256 insertions(+), 7 deletions(-) create mode 100644 tests/ApplicationBridge/.env create mode 100644 tests/ApplicationBridge/AccessTokenFileStorage.php create mode 100644 tests/ApplicationBridge/AccessTokenRepositoryInterface.php create mode 100644 tests/ApplicationBridge/ApplicationCredentialsProvider.php create mode 100644 tests/ApplicationBridge/index.php create mode 100644 tests/ApplicationBridge/install.php diff --git a/.gitignore b/.gitignore index 6ae5ed5a..8f9344f1 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ 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/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/AccessTokenFileStorage.php b/tests/ApplicationBridge/AccessTokenFileStorage.php new file mode 100644 index 00000000..e113ac86 --- /dev/null +++ b/tests/ApplicationBridge/AccessTokenFileStorage.php @@ -0,0 +1,61 @@ +filesystem->exists($this->getFileName()); + } + + /** + * @throws FileNotFoundException + * @throws JsonException + */ + public function getAccessToken(): AccessToken + { + 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 AccessToken::initFromArray(json_decode($payload, true, 512, JSON_THROW_ON_ERROR)); + } + + public function saveAccessToken(AccessToken $accessToken): void + { + $accessTokenPayload = json_encode([ + 'access_token' => $accessToken->getAccessToken(), + 'refresh_token' => $accessToken->getRefreshToken(), + 'expires' => $accessToken->getExpires() + ], JSON_THROW_ON_ERROR); + + $this->filesystem->dumpFile($this->getFileName(), $accessTokenPayload); + } + + public function saveRenewedAccessToken(RenewedAccessToken $renewedAccessToken): void + { + $this->saveAccessToken($renewedAccessToken->getAccessToken()); + } +} \ No newline at end of file diff --git a/tests/ApplicationBridge/AccessTokenRepositoryInterface.php b/tests/ApplicationBridge/AccessTokenRepositoryInterface.php new file mode 100644 index 00000000..217a215d --- /dev/null +++ b/tests/ApplicationBridge/AccessTokenRepositoryInterface.php @@ -0,0 +1,20 @@ +repository->isAvailable(); + } + + public function saveAccessToken(AccessToken $accessToken): void + { + $this->repository->saveAccessToken($accessToken); + } + + /** + * @throws InvalidArgumentException + */ + public function getCredentials(ApplicationProfile $applicationProfile, string $domainUrl): Credentials + { + return new Credentials( + null, + $this->repository->getAccessToken(), + $applicationProfile, + $domainUrl + ); + } + + #[NoReturn] + public function onAuthTokenRenewedEventListener(AuthTokenRenewedEvent $event): void + { + // update credentials + $this->repository->saveRenewedAccessToken($event->getRenewedToken()); + } + + public static function buildProviderForLocalApplication(): self + { + return new ApplicationCredentialsProvider(new AccessTokenFileStorage(new Filesystem())); + } +} \ No newline at end of file diff --git a/tests/ApplicationBridge/index.php b/tests/ApplicationBridge/index.php new file mode 100644 index 00000000..5ac9ce4e --- /dev/null +++ b/tests/ApplicationBridge/index.php @@ -0,0 +1,57 @@ + +
+
+    
+    
+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 = AccessToken::initFromPlacementRequest($request); +$b24Service = $b24ServiceFactory->initFromRequest($appProfile, $accessToken, $_REQUEST['DOMAIN']); + +// save new access token for integration tests +$credentialsProvider = ApplicationCredentialsProvider::buildProviderForLocalApplication(); +$credentialsProvider->saveAccessToken($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..eae01705 --- /dev/null +++ b/tests/ApplicationBridge/install.php @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/tests/Integration/Fabric.php b/tests/Integration/Fabric.php index 3d2357c9..ad4a4ec1 100644 --- a/tests/Integration/Fabric.php +++ b/tests/Integration/Fabric.php @@ -9,14 +9,21 @@ 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\AccessTokenFileStorage; +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 @@ -26,12 +33,18 @@ class Fabric { /** + * @param bool $isNeedApplicationCredentials some rest-api methods need application credentials, incoming webhook doesn't work for call this methods * @return ServiceBuilder - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @throws InvalidArgumentException */ - public static function getServiceBuilder(): ServiceBuilder + public static function getServiceBuilder(bool $isNeedApplicationCredentials = false): ServiceBuilder { - return new ServiceBuilder(self::getCore(), self::getBatchService(), self::getBulkItemsReader(), self::getLogger()); + return new ServiceBuilder( + self::getCore($isNeedApplicationCredentials), + self::getBatchService(), + self::getBulkItemsReader(), + self::getLogger() + ); } /** @@ -52,12 +65,13 @@ public static function getBulkItemsReader(): BulkItemsReaderInterface } /** - * @return \Bitrix24\SDK\Core\Contracts\CoreInterface - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @param bool $isNeedApplicationCredentials + * @return CoreInterface + * @throws InvalidArgumentException */ - public static function getCore(): CoreInterface + public static function getCore(bool $isNeedApplicationCredentials = false): CoreInterface { - return (new CoreBuilder()) + $default = (new CoreBuilder()) ->withLogger(self::getLogger()) ->withCredentials( Credentials::createFromWebhook( @@ -65,6 +79,33 @@ public static function getCore(): CoreInterface ) ) ->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; } /** From 6e0fb858e71749bde49ab7ea9bfd48f228cd9a59 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 20 Jun 2024 00:28:09 +0600 Subject: [PATCH 055/138] Add TTS voices and InfoCall services in Voximplant The commit includes the addition of services that enable the management of TTS Voices and InfoCalls in Voximplant. The new services include methods for listing available voices for speech generation and initiating calls with specific parameters. Corresponding test cases and results structure for these services were also added and defined. Signed-off-by: mesilov --- CHANGELOG.md | 8 +++- .../Result/VoximplantVoiceItemResult.php | 15 +++++++ .../Voices/Result/VoximplantVoicesResult.php | 29 +++++++++++++ .../Voximplant/TTS/Voices/Service/Batch.php | 17 ++++++++ .../Voximplant/TTS/Voices/Service/Voices.php | 38 +++++++++++++++++ .../Voximplant/VoximplantServiceBuilder.php | 26 ++++++++++++ .../TTS/Voices/Service/VoicesTest.php | 41 +++++++++++++++++++ 7 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 src/Services/Telephony/Voximplant/TTS/Voices/Result/VoximplantVoiceItemResult.php create mode 100644 src/Services/Telephony/Voximplant/TTS/Voices/Result/VoximplantVoicesResult.php create mode 100644 src/Services/Telephony/Voximplant/TTS/Voices/Service/Batch.php create mode 100644 src/Services/Telephony/Voximplant/TTS/Voices/Service/Voices.php create mode 100644 tests/Integration/Services/Telephony/Voximplant/TTS/Voices/Service/VoicesTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index f9ab53a6..eff79eb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,7 +52,7 @@ ### Changed -* update scope `telephony`, scope fully rewritten +* ❗️ 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 @@ -81,6 +81,12 @@ * `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 + * `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. * add `TranscriptMessage` – data structure for transcript message item * add `TranscriptMessageSide` – enum for describe side of diarization * add `CallType` – call types enum 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..1e249e33 --- /dev/null +++ b/src/Services/Telephony/Voximplant/TTS/Voices/Result/VoximplantVoiceItemResult.php @@ -0,0 +1,15 @@ +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..cc6cea9a --- /dev/null +++ b/src/Services/Telephony/Voximplant/TTS/Voices/Service/Batch.php @@ -0,0 +1,17 @@ + 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 + */ + 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/VoximplantServiceBuilder.php b/src/Services/Telephony/Voximplant/VoximplantServiceBuilder.php index 69f86012..4a4a80ec 100644 --- a/src/Services/Telephony/Voximplant/VoximplantServiceBuilder.php +++ b/src/Services/Telephony/Voximplant/VoximplantServiceBuilder.php @@ -36,4 +36,30 @@ public function user(): Telephony\Voximplant\User\Service\User 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__]; + } } \ 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..a4f1af88 --- /dev/null +++ b/tests/Integration/Services/Telephony/Voximplant/TTS/Voices/Service/VoicesTest.php @@ -0,0 +1,41 @@ +voices->get(); + $this->assertGreaterThanOrEqual(1, count($res->getVoices())); + } + + protected function setUp(): void + { + $this->voices = Fabric::getServiceBuilder()->getTelephonyScope()->getVoximplantServiceBuilder()->ttsVoices(); + } +} \ No newline at end of file From af2ef1caa620a25690462154d910e14b53f177aa Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 20 Jun 2024 23:03:18 +0600 Subject: [PATCH 056/138] Add new services for managing Voximplant sip lines This update introduces new services to handle Voximplant sip lines. Features added include setting the SIP line as outgoing by default, returning all available outgoing lines, and getting or setting the line by default for outgoing calls. Relevant tests are also incorporated to ensure functionality. Signed-off-by: mesilov --- CHANGELOG.md | 5 ++ .../Result/VoximplantLineIdItemResult.php | 14 ++++ .../Line/Result/VoximplantLineIdResult.php | 17 ++++ .../Line/Result/VoximplantLineItemResult.php | 15 ++++ .../Line/Result/VoximplantLinesResult.php | 30 +++++++ .../Voximplant/Line/Service/Batch.php | 17 ++++ .../Voximplant/Line/Service/Line.php | 78 +++++++++++++++++++ .../Voximplant/VoximplantServiceBuilder.php | 13 ++++ .../Voximplant/Line/Service/LineTest.php | 76 ++++++++++++++++++ 9 files changed, 265 insertions(+) create mode 100644 src/Services/Telephony/Voximplant/Line/Result/VoximplantLineIdItemResult.php create mode 100644 src/Services/Telephony/Voximplant/Line/Result/VoximplantLineIdResult.php create mode 100644 src/Services/Telephony/Voximplant/Line/Result/VoximplantLineItemResult.php create mode 100644 src/Services/Telephony/Voximplant/Line/Result/VoximplantLinesResult.php create mode 100644 src/Services/Telephony/Voximplant/Line/Service/Batch.php create mode 100644 src/Services/Telephony/Voximplant/Line/Service/Line.php create mode 100644 tests/Integration/Services/Telephony/Voximplant/Line/Service/LineTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index eff79eb4..587b392d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -83,6 +83,11 @@ * `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 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..ddbdffec --- /dev/null +++ b/src/Services/Telephony/Voximplant/Line/Result/VoximplantLineIdItemResult.php @@ -0,0 +1,14 @@ + $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..616591df --- /dev/null +++ b/src/Services/Telephony/Voximplant/Line/Result/VoximplantLineItemResult.php @@ -0,0 +1,15 @@ +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..44e54e41 --- /dev/null +++ b/src/Services/Telephony/Voximplant/Line/Service/Batch.php @@ -0,0 +1,17 @@ +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 + */ + 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 + */ + 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. + * @return UserInterfaceDialogCallResult + * @throws BaseException + * @throws TransportException + */ + 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/VoximplantServiceBuilder.php b/src/Services/Telephony/Voximplant/VoximplantServiceBuilder.php index 4a4a80ec..85ebc734 100644 --- a/src/Services/Telephony/Voximplant/VoximplantServiceBuilder.php +++ b/src/Services/Telephony/Voximplant/VoximplantServiceBuilder.php @@ -62,4 +62,17 @@ public function ttsVoices(): Telephony\Voximplant\TTS\Voices\Service\Voices 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__]; + } } \ 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..01730870 --- /dev/null +++ b/tests/Integration/Services/Telephony/Voximplant/Line/Service/LineTest.php @@ -0,0 +1,76 @@ +toRfc4122(); + $serverUrl = 'supersip.io'; + $login = Uuid::v4()->toRfc4122(); + $password = Uuid::v4()->toRfc4122(); + + $addedLine = $this->sip->add( + PbxType::cloud, + $sipTitle, + $serverUrl, + $login, + $password + ); + + $this->assertTrue($this->line->outgoingSipSet($addedLine->getLine()->ID)->isSuccess()); + $this->sip->delete($addedLine->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 From 342c730c0be76c152acd4e9e8d85cf52c21ab905 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 20 Jun 2024 23:44:02 +0600 Subject: [PATCH 057/138] Add Voximplant InfoCall functionalities and related tests This commit includes addition of InfoCall Service under Voximplant telephony, with function to start a call with text or sound. Accompanying unit tests for the functionality have also been created. Additionally, minor code refactoring and variable renaming have taken place in voice test classes for clarity. Signed-off-by: mesilov --- .../Result/VoximplantInfoCallItemResult.php | 15 +++++ .../Result/VoximplantInfoCallResult.php | 15 +++++ .../Voximplant/InfoCall/Service/Batch.php | 17 +++++ .../Voximplant/InfoCall/Service/InfoCall.php | 57 ++++++++++++++++ .../Voximplant/Line/Service/Line.php | 1 - tests/Builders/DemoDataGenerator.php | 15 +++++ .../InfoCall/Service/InfoCallTest.php | 66 +++++++++++++++++++ .../Voximplant/Line/Service/LineTest.php | 1 + .../TTS/Voices/Service/VoicesTest.php | 4 +- 9 files changed, 188 insertions(+), 3 deletions(-) create mode 100644 src/Services/Telephony/Voximplant/InfoCall/Result/VoximplantInfoCallItemResult.php create mode 100644 src/Services/Telephony/Voximplant/InfoCall/Result/VoximplantInfoCallResult.php create mode 100644 src/Services/Telephony/Voximplant/InfoCall/Service/Batch.php create mode 100644 src/Services/Telephony/Voximplant/InfoCall/Service/InfoCall.php create mode 100644 tests/Builders/DemoDataGenerator.php create mode 100644 tests/Integration/Services/Telephony/Voximplant/InfoCall/Service/InfoCallTest.php 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..6ca811c2 --- /dev/null +++ b/src/Services/Telephony/Voximplant/InfoCall/Result/VoximplantInfoCallItemResult.php @@ -0,0 +1,15 @@ +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..54f1bf39 --- /dev/null +++ b/src/Services/Telephony/Voximplant/InfoCall/Service/Batch.php @@ -0,0 +1,17 @@ +core->call('voximplant.infocall.startwithtext', [ + 'FROM_LINE' => $lineId, + 'TO_NUMBER' => $toNumber, + 'TEXT_TO_PRONOUNCE' => $text, + 'VOICE' => $voiceCode + ])); + } + + 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/Service/Line.php b/src/Services/Telephony/Voximplant/Line/Service/Line.php index 3779e7eb..472dd8df 100644 --- a/src/Services/Telephony/Voximplant/Line/Service/Line.php +++ b/src/Services/Telephony/Voximplant/Line/Service/Line.php @@ -65,7 +65,6 @@ public function outgoingGet(): VoximplantLineIdResult * 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. - * @return UserInterfaceDialogCallResult * @throws BaseException * @throws TransportException */ diff --git a/tests/Builders/DemoDataGenerator.php b/tests/Builders/DemoDataGenerator.php new file mode 100644 index 00000000..ef50e9c0 --- /dev/null +++ b/tests/Builders/DemoDataGenerator.php @@ -0,0 +1,15 @@ +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(), + '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(), + 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 index 01730870..cb37da80 100644 --- a/tests/Integration/Services/Telephony/Voximplant/Line/Service/LineTest.php +++ b/tests/Integration/Services/Telephony/Voximplant/Line/Service/LineTest.php @@ -24,6 +24,7 @@ class LineTest extends TestCase { private Line $line; + private Sip $sip; #[Test] diff --git a/tests/Integration/Services/Telephony/Voximplant/TTS/Voices/Service/VoicesTest.php b/tests/Integration/Services/Telephony/Voximplant/TTS/Voices/Service/VoicesTest.php index a4f1af88..3d0c1649 100644 --- a/tests/Integration/Services/Telephony/Voximplant/TTS/Voices/Service/VoicesTest.php +++ b/tests/Integration/Services/Telephony/Voximplant/TTS/Voices/Service/VoicesTest.php @@ -30,8 +30,8 @@ class VoicesTest extends TestCase #[TestDox('test list available voices for generation of speech')] public function testGet(): void { - $res = $this->voices->get(); - $this->assertGreaterThanOrEqual(1, count($res->getVoices())); + $voximplantVoicesResult = $this->voices->get(); + $this->assertGreaterThanOrEqual(1, count($voximplantVoicesResult->getVoices())); } protected function setUp(): void From cf07aadd5b8f99fc08ec0fb66d4ad06eb319e810 Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 21 Jun 2024 00:51:38 +0600 Subject: [PATCH 058/138] Add telephony scope links retrieval functionality Extended Software Development Kit (SDK) services for telephony with a function to fetch links for browsing telephony scope pages. Introduced corresponding Voximplant service classes and related unit tests. The new method fetches a set of vital navigation links, helping to facilitate telephony operations by users. Signed-off-by: mesilov --- CHANGELOG.md | 2 + .../Url/Result/VoximplantPagesItemResult.php | 17 +++++++++ .../Url/Result/VoximplantPagesResult.php | 15 ++++++++ .../Voximplant/Url/Service/Batch.php | 17 +++++++++ .../Telephony/Voximplant/Url/Service/Url.php | 37 +++++++++++++++++++ .../Voximplant/VoximplantServiceBuilder.php | 13 +++++++ .../Voximplant/Url/Service/UrlTest.php | 33 +++++++++++++++++ 7 files changed, 134 insertions(+) create mode 100644 src/Services/Telephony/Voximplant/Url/Result/VoximplantPagesItemResult.php create mode 100644 src/Services/Telephony/Voximplant/Url/Result/VoximplantPagesResult.php create mode 100644 src/Services/Telephony/Voximplant/Url/Service/Batch.php create mode 100644 src/Services/Telephony/Voximplant/Url/Service/Url.php create mode 100644 tests/Integration/Services/Telephony/Voximplant/Url/Service/UrlTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 587b392d..0f559724 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -92,6 +92,8 @@ * `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 `TranscriptMessage` – data structure for transcript message item * add `TranscriptMessageSide` – enum for describe side of diarization * add `CallType` – call types enum 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..67eab9fa --- /dev/null +++ b/src/Services/Telephony/Voximplant/Url/Result/VoximplantPagesItemResult.php @@ -0,0 +1,17 @@ +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..1f5e6b7b --- /dev/null +++ b/src/Services/Telephony/Voximplant/Url/Service/Batch.php @@ -0,0 +1,17 @@ +core->call('voximplant.url.get')); + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Voximplant/VoximplantServiceBuilder.php b/src/Services/Telephony/Voximplant/VoximplantServiceBuilder.php index 85ebc734..99215854 100644 --- a/src/Services/Telephony/Voximplant/VoximplantServiceBuilder.php +++ b/src/Services/Telephony/Voximplant/VoximplantServiceBuilder.php @@ -75,4 +75,17 @@ public function line(): Telephony\Voximplant\Line\Service\Line 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/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..8f6eedb9 --- /dev/null +++ b/tests/Integration/Services/Telephony/Voximplant/Url/Service/UrlTest.php @@ -0,0 +1,33 @@ +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 From bb0d2473f2f5ff57a26c23be9899ec8fb724247f Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 21 Jun 2024 01:29:22 +0600 Subject: [PATCH 059/138] Add getConnectorStatus method to Sip service This commit adds a new method, getConnectorStatus, to the Sip service in the telephony module. This new method retrieves the current status of the SIP Connector. It also includes a corresponding test case in the SipTest integration test and updates the CHANGELOG.md file to document this new functionality. Signed-off-by: mesilov --- CHANGELOG.md | 1 + .../Result/SipConnectorStatusItemResult.php | 34 +++++++++++++++++++ .../Sip/Result/SipConnectorStatusResult.php | 15 ++++++++ .../Telephony/Voximplant/Sip/Service/Sip.php | 18 +++++++--- .../Telephony/Voximplant/Sip/SipTest.php | 8 ++++- 5 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 src/Services/Telephony/Voximplant/Sip/Result/SipConnectorStatusItemResult.php create mode 100644 src/Services/Telephony/Voximplant/Sip/Result/SipConnectorStatusResult.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f559724..4a74be31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -77,6 +77,7 @@ * `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 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..9d13191e --- /dev/null +++ b/src/Services/Telephony/Voximplant/Sip/Result/SipConnectorStatusItemResult.php @@ -0,0 +1,34 @@ +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..e6a521c3 --- /dev/null +++ b/src/Services/Telephony/Voximplant/Sip/Result/SipConnectorStatusResult.php @@ -0,0 +1,15 @@ +getCoreResponse()->getResponseData()->getResult()); + } +} \ 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 index 66966af1..09c91902 100644 --- a/src/Services/Telephony/Voximplant/Sip/Service/Sip.php +++ b/src/Services/Telephony/Voximplant/Sip/Service/Sip.php @@ -9,15 +9,12 @@ use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; use Bitrix24\SDK\Core\Exceptions\TransportException; use Bitrix24\SDK\Core\Result\DeletedItemResult; -use Bitrix24\SDK\Core\Result\EmptyResult; use Bitrix24\SDK\Core\Result\UpdatedItemResult; use Bitrix24\SDK\Services\AbstractService; use Bitrix24\SDK\Services\Telephony\Common\PbxType; -use Bitrix24\SDK\Services\Telephony\ExternalLine\Result\ExternalLineAddedResult; -use Bitrix24\SDK\Services\Telephony\ExternalLine\Result\ExternalLinesResult; +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\SipLineStatusItemResult; use Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result\SipLineStatusResult; use Psr\Log\LoggerInterface; @@ -32,6 +29,19 @@ public function __construct( 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 + */ + 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. * diff --git a/tests/Integration/Services/Telephony/Voximplant/Sip/SipTest.php b/tests/Integration/Services/Telephony/Voximplant/Sip/SipTest.php index 1291c748..da0c3bb4 100644 --- a/tests/Integration/Services/Telephony/Voximplant/Sip/SipTest.php +++ b/tests/Integration/Services/Telephony/Voximplant/Sip/SipTest.php @@ -7,7 +7,6 @@ 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\Tests\Integration\Fabric; use PHPUnit\Framework\Attributes\CoversClass; @@ -21,6 +20,13 @@ 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 From 67fef659e840dfe296d927e35ed585ddc31af7c5 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 27 Jun 2024 02:06:54 +0600 Subject: [PATCH 060/138] Add telephony events and EventManager for handling them This update introduces several telephony-related events and an EventManager to manage them. The events include 'OnExternalCallBackStart', 'OnExternalCallStart', 'OnVoximplantCallEnd', 'OnVoximplantCallInit', 'OnVoximplantCallStart'. This will significantly enhance the functionality of the telephony feature in the application by allowing more interaction possibilities. Signed-off-by: mesilov --- CHANGELOG.md | 8 +- .../Requests/Events/AbstractEventRequest.php | 25 ++-- .../Requests/Events/EventAuthItem.php | 42 +++++++ .../Requests/Events/EventInterface.php | 21 ++++ .../OnApplicationInstall.php | 11 -- .../OnApplicationUninstall.php | 11 -- src/Core/Credentials/AccessToken.php | 43 ++++--- src/Core/Credentials/Endpoints.php | 2 +- src/Core/Credentials/Scope.php | 2 +- .../Main/Common/EventHandlerMetadata.php | 23 ++++ src/Services/Main/MainServiceBuilder.php | 12 ++ src/Services/Main/Service/EventManager.php | 108 ++++++++++++++++++ .../Telephony/Common/CallFailedCode.php | 20 ++++ .../OnExternalCallBackStart.php | 17 +++ .../OnExternalCallBackStartEventPayload.php | 28 +++++ .../OnExternalCallStart.php | 17 +++ .../OnExternalCallStartEventPayload.php | 34 ++++++ .../OnVoximplantCallEnd.php | 13 +++ .../OnVoximplantCallEndEventPayload.php | 43 +++++++ .../OnVoximplantCallInit.php | 17 +++ .../OnVoximplantCallInitEventPayload.php | 27 +++++ .../OnVoximplantCallStart.php | 17 +++ .../OnVoximplantCallStartEventPayload.php | 23 ++++ .../Events/TelephonyEventsFabric.php | 38 ++++++ 24 files changed, 552 insertions(+), 50 deletions(-) create mode 100644 src/Application/Requests/Events/EventAuthItem.php create mode 100644 src/Application/Requests/Events/EventInterface.php create mode 100644 src/Services/Main/Common/EventHandlerMetadata.php create mode 100644 src/Services/Main/Service/EventManager.php create mode 100644 src/Services/Telephony/Common/CallFailedCode.php create mode 100644 src/Services/Telephony/Events/OnExternalCallBackStart/OnExternalCallBackStart.php create mode 100644 src/Services/Telephony/Events/OnExternalCallBackStart/OnExternalCallBackStartEventPayload.php create mode 100644 src/Services/Telephony/Events/OnExternalCallStart/OnExternalCallStart.php create mode 100644 src/Services/Telephony/Events/OnExternalCallStart/OnExternalCallStartEventPayload.php create mode 100644 src/Services/Telephony/Events/OnVoximplantCallEnd/OnVoximplantCallEnd.php create mode 100644 src/Services/Telephony/Events/OnVoximplantCallEnd/OnVoximplantCallEndEventPayload.php create mode 100644 src/Services/Telephony/Events/OnVoximplantCallInit/OnVoximplantCallInit.php create mode 100644 src/Services/Telephony/Events/OnVoximplantCallInit/OnVoximplantCallInitEventPayload.php create mode 100644 src/Services/Telephony/Events/OnVoximplantCallStart/OnVoximplantCallStart.php create mode 100644 src/Services/Telephony/Events/OnVoximplantCallStart/OnVoximplantCallStartEventPayload.php create mode 100644 src/Services/Telephony/Events/TelephonyEventsFabric.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a74be31..f49f4afb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -94,7 +94,13 @@ 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. + * `get` - returns a set of links for browsing telephony scope pages. + * add events with payload: + * `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 diff --git a/src/Application/Requests/Events/AbstractEventRequest.php b/src/Application/Requests/Events/AbstractEventRequest.php index ca344c96..750e5a8e 100644 --- a/src/Application/Requests/Events/AbstractEventRequest.php +++ b/src/Application/Requests/Events/AbstractEventRequest.php @@ -7,14 +7,15 @@ use Bitrix24\SDK\Application\Requests\AbstractRequest; use Symfony\Component\HttpFoundation\Request; -abstract class AbstractEventRequest extends AbstractRequest +abstract class AbstractEventRequest extends AbstractRequest implements EventInterface { protected string $eventCode; protected int $timestamp; protected array $eventPayload; + protected int $eventId; /** - * @param \Symfony\Component\HttpFoundation\Request $request + * @param Request $request */ public function __construct(Request $request) { @@ -25,29 +26,31 @@ public function __construct(Request $request) $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; } - /** - * @return int - */ public function getTimestamp(): int { return $this->timestamp; } - /** - * @return string - */ public function getEventCode(): string { return $this->eventCode; } - /** - * @return array - */ public function getEventPayload(): array { return $this->eventPayload; } + + 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..f6b44103 --- /dev/null +++ b/src/Application/Requests/Events/EventAuthItem.php @@ -0,0 +1,42 @@ + (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..6358564e --- /dev/null +++ b/src/Application/Requests/Events/EventInterface.php @@ -0,0 +1,21 @@ +eventPayload['data']); } - - /** - * @return \Bitrix24\SDK\Application\Requests\Events\OnApplicationInstall\Auth - */ - public function getAuth(): Auth - { - return new Auth($this->eventPayload['auth']); - } } \ No newline at end of file diff --git a/src/Application/Requests/Events/OnApplicationUninstall/OnApplicationUninstall.php b/src/Application/Requests/Events/OnApplicationUninstall/OnApplicationUninstall.php index 1503ee54..a90450a1 100644 --- a/src/Application/Requests/Events/OnApplicationUninstall/OnApplicationUninstall.php +++ b/src/Application/Requests/Events/OnApplicationUninstall/OnApplicationUninstall.php @@ -8,19 +8,8 @@ class OnApplicationUninstall extends AbstractEventRequest { - /** - * @return \Bitrix24\SDK\Application\Requests\Events\OnApplicationUninstall\ApplicationData - */ public function getApplicationData(): ApplicationData { return new ApplicationData($this->eventPayload['data']); } - - /** - * @return \Bitrix24\SDK\Application\Requests\Events\OnApplicationUninstall\Auth - */ - public function getAuth(): Auth - { - return new Auth($this->eventPayload['auth']); - } } \ No newline at end of file diff --git a/src/Core/Credentials/AccessToken.php b/src/Core/Credentials/AccessToken.php index 7ecf5bfb..54e26478 100644 --- a/src/Core/Credentials/AccessToken.php +++ b/src/Core/Credentials/AccessToken.php @@ -8,43 +8,47 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation; -/** - * Class AccessToken - * - * @package Bitrix24\SDK\Core\Credentials - */ class AccessToken { protected string $accessToken; - protected string $refreshToken; + protected ?string $refreshToken; protected int $expires; + protected ?int $expiresIn; /** * AccessToken constructor. * * @param string $accessToken - * @param string $refreshToken - * @param int $expires + * @param string|null $refreshToken + * @param int $expires + * @param int|null $expiresIn */ - public function __construct(string $accessToken, string $refreshToken, int $expires) + public function __construct(string $accessToken, ?string $refreshToken, int $expires, ?int $expiresIn = null) { $this->accessToken = $accessToken; $this->refreshToken = $refreshToken; $this->expires = $expires; + $this->expiresIn = $expiresIn; } /** - * @return string + * Is this one-off token from event + * + * One-off tokens do not have refresh token field + * + * @return bool */ + public function isOneOff(): bool + { + return $this->refreshToken === null; + } + public function getAccessToken(): string { return $this->accessToken; } - /** - * @return string - */ - public function getRefreshToken(): string + public function getRefreshToken(): ?string { return $this->refreshToken; } @@ -85,6 +89,17 @@ public static function initFromWorkflowRequest(Request $request): self return self::initFromArray($requestFields['auth']); } + public static function initFromEventRequest(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 */ diff --git a/src/Core/Credentials/Endpoints.php b/src/Core/Credentials/Endpoints.php index f88a3da7..9c826eb7 100644 --- a/src/Core/Credentials/Endpoints.php +++ b/src/Core/Credentials/Endpoints.php @@ -15,7 +15,7 @@ public function __construct( */ public string $authServerUrl, /** - * @phpstan-param non-empty-string $authServerUrl + * @phpstan-param non-empty-string $clientUrl */ public string $clientUrl, ) diff --git a/src/Core/Credentials/Scope.php b/src/Core/Credentials/Scope.php index 38458bdb..b353d598 100644 --- a/src/Core/Credentials/Scope.php +++ b/src/Core/Credentials/Scope.php @@ -111,7 +111,7 @@ public function getScopeCodes(): array } /** - * @throws \Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException + * @throws UnknownScopeCodeException */ public static function initFromString(string $scope): self { diff --git a/src/Services/Main/Common/EventHandlerMetadata.php b/src/Services/Main/Common/EventHandlerMetadata.php new file mode 100644 index 00000000..3c9dd2ca --- /dev/null +++ b/src/Services/Main/Common/EventHandlerMetadata.php @@ -0,0 +1,23 @@ +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 index ce6f34ce..6a4f525b 100644 --- a/src/Services/Main/MainServiceBuilder.php +++ b/src/Services/Main/MainServiceBuilder.php @@ -5,6 +5,7 @@ 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; @@ -38,4 +39,15 @@ public function event(): Event 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/Service/EventManager.php b/src/Services/Main/Service/EventManager.php new file mode 100644 index 00000000..af2cbe58 --- /dev/null +++ b/src/Services/Main/Service/EventManager.php @@ -0,0 +1,108 @@ +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 $installedHandler) { + $this->logger->debug('bindEventHandlers.isHandlerInstalled', [ + 'handlerToInstallCode' => $eventHandler->code, + 'handlerToInstallUrl' => $eventHandler->handlerUrl, + 'isInstalled' => $eventHandler->isInstalled($installedHandler) + ]); + if ($eventHandler->isInstalled($installedHandler)) { + $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 + { + $activeHandlers = $this->eventService->get(); + if (count($activeHandlers->getEventHandlers()) === 0) { + return $activeHandlers; + } + + $handlersToUnbind = $activeHandlers->getEventHandlers(); + // todo replace to batch call + foreach ($handlersToUnbind as $itemHandler) { + $this->logger->debug('unbindAllEventHandlers.handler', [ + 'code' => $itemHandler->event, + 'handler' => $itemHandler->handler, + ]); + $this->eventService->unbind( + $itemHandler->event, + $itemHandler->handler + ); + } + return $activeHandlers; + } +} \ No newline at end of file diff --git a/src/Services/Telephony/Common/CallFailedCode.php b/src/Services/Telephony/Common/CallFailedCode.php new file mode 100644 index 00000000..328578a9 --- /dev/null +++ b/src/Services/Telephony/Common/CallFailedCode.php @@ -0,0 +1,20 @@ +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..c78653ee --- /dev/null +++ b/src/Services/Telephony/Events/OnExternalCallBackStart/OnExternalCallBackStartEventPayload.php @@ -0,0 +1,28 @@ + (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..d9ec396d --- /dev/null +++ b/src/Services/Telephony/Events/OnExternalCallStart/OnExternalCallStart.php @@ -0,0 +1,17 @@ +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..7a57d2af --- /dev/null +++ b/src/Services/Telephony/Events/OnExternalCallStart/OnExternalCallStartEventPayload.php @@ -0,0 +1,34 @@ + (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..d277a1c9 --- /dev/null +++ b/src/Services/Telephony/Events/OnVoximplantCallEnd/OnVoximplantCallEnd.php @@ -0,0 +1,13 @@ + (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..f21a93fb --- /dev/null +++ b/src/Services/Telephony/Events/OnVoximplantCallInit/OnVoximplantCallInit.php @@ -0,0 +1,17 @@ +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..057a66dc --- /dev/null +++ b/src/Services/Telephony/Events/OnVoximplantCallInit/OnVoximplantCallInitEventPayload.php @@ -0,0 +1,27 @@ + (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..186aeecf --- /dev/null +++ b/src/Services/Telephony/Events/OnVoximplantCallStart/OnVoximplantCallStart.php @@ -0,0 +1,17 @@ +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..e7b6ff44 --- /dev/null +++ b/src/Services/Telephony/Events/OnVoximplantCallStart/OnVoximplantCallStartEventPayload.php @@ -0,0 +1,23 @@ + (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..aa1f6e86 --- /dev/null +++ b/src/Services/Telephony/Events/TelephonyEventsFabric.php @@ -0,0 +1,38 @@ +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 From d095e06820c9f107aa3826e7dd37ed2e5ea458c4 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 27 Jun 2024 09:57:48 +0600 Subject: [PATCH 061/138] Update TelephonyEventsFabric and CHANGELOG.md A blank line was added to the TelephonyEventsFabric file for improved readability. The CHANGELOG was also updated to include the addition of events with payload and `TelephonyEventsFabric`. A section for "Deleted" events was prepared but is currently empty. Signed-off-by: mesilov --- CHANGELOG.md | 5 ++++- src/Services/Telephony/Events/TelephonyEventsFabric.php | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f49f4afb..41e7d83c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -95,7 +95,7 @@ * `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: + * 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). @@ -108,6 +108,9 @@ * add `PbxType` – pbx type enum * add `SipRegistrationStatus` – pbx sip line registration status +### Deleted + + ## 2.0-beta.2 — 1.04.2024 ### Changed diff --git a/src/Services/Telephony/Events/TelephonyEventsFabric.php b/src/Services/Telephony/Events/TelephonyEventsFabric.php index aa1f6e86..6bfe978d 100644 --- a/src/Services/Telephony/Events/TelephonyEventsFabric.php +++ b/src/Services/Telephony/Events/TelephonyEventsFabric.php @@ -26,6 +26,7 @@ public function create(Request $request): ?EventInterface 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), From f1688fb0f7247ea391bf981a894554ca291d6c47 Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 27 Jun 2024 10:08:59 +0600 Subject: [PATCH 062/138] Remove OnApplicationInstall and OnApplicationUninstall Auth classes The OnApplicationInstall/Auth.php and OnApplicationUninstall/Auth.php files have been deleted. These were unnecessary as they were no longer being used in the application, simplifying the overall structure. Signed-off-by: mesilov --- .../Events/OnApplicationInstall/Auth.php | 25 ------------------- .../Events/OnApplicationUninstall/Auth.php | 18 ------------- 2 files changed, 43 deletions(-) delete mode 100644 src/Application/Requests/Events/OnApplicationInstall/Auth.php delete mode 100644 src/Application/Requests/Events/OnApplicationUninstall/Auth.php diff --git a/src/Application/Requests/Events/OnApplicationInstall/Auth.php b/src/Application/Requests/Events/OnApplicationInstall/Auth.php deleted file mode 100644 index ba2c1a72..00000000 --- a/src/Application/Requests/Events/OnApplicationInstall/Auth.php +++ /dev/null @@ -1,25 +0,0 @@ - Date: Fri, 28 Jun 2024 01:01:03 +0600 Subject: [PATCH 063/138] Update changelog Signed-off-by: mesilov --- CHANGELOG.md | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41e7d83c..7d764824 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,18 +40,26 @@ * `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 [Rector](https://github.com/rectorphp/rector) for improve code quality and speed up releases cycle -* add `Bitrix24\SDK\Core\Exceptions\UserNotFoundOrIsNotActiveException` exception if user not found, or it is not active * 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 +* improve DX - add [Rector](https://github.com/rectorphp/rector) for improve code quality and speed up releases cycle ### Changed - * ❗️ update scope `telephony`, scope fully rewritten * `ExternalCall` – work with external call: * `getCallRecordUploadUrl` – get url for upload call record file @@ -107,9 +115,16 @@ * add `CrmEntityType` – crm entity type enum * add `PbxType` – pbx type enum * add `SipRegistrationStatus` – pbx sip line registration status +* change signature `Bitrix24\SDK\Core\Credentials\AccessToken::getRefreshToken()?string;` - add nullable option for event tokens ### 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` + ## 2.0-beta.2 — 1.04.2024 From 6c389173e2de8ab469e7cdba24f24b308442155c Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 28 Jun 2024 02:11:09 +0600 Subject: [PATCH 064/138] Fix typecast error for User ID Signed-off-by: mesilov --- CHANGELOG.md | 5 ++- Makefile | 4 +- phpstan.neon.dist | 1 + phpunit.xml.dist | 3 ++ rector.php | 2 + src/Services/User/Result/UserItemResult.php | 16 ++++---- src/Services/User/Service/User.php | 14 +------ src/Services/User/UserServiceBuilder.php | 5 --- .../Services/User/Service/UserTest.php | 40 +++++++++---------- 9 files changed, 42 insertions(+), 48 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d764824..b6115ddc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -124,7 +124,10 @@ * 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) ## 2.0-beta.2 — 1.04.2024 diff --git a/Makefile b/Makefile index 480db6f4..5c55b787 100644 --- a/Makefile +++ b/Makefile @@ -16,4 +16,6 @@ test-unit: test-integration-scope-telephony: vendor/bin/phpunit --testsuite integration_tests_scope_telephony test-integration-scope-workflows: - vendor/bin/phpunit --testsuite integration_tests_scope_workflows \ No newline at end of file + vendor/bin/phpunit --testsuite integration_tests_scope_workflows +test-integration-scope-user: + vendor/bin/phpunit --testsuite integration_tests_scope_user \ No newline at end of file diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 06170dda..6a8ea16d 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -3,6 +3,7 @@ parameters: paths: - src/ - tests/Integration/Services/Telephony + - tests/Integration/Services/User bootstrapFiles: - tests/bootstrap.php parallel: diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 3555dd5e..d16b93db 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -13,6 +13,9 @@ ./tests/Integration/Services/Telephony/ + + ./tests/Integration/Services/User/ + ./tests/Integration/Services/Workflows/ diff --git a/rector.php b/rector.php index 85ed9bf9..d4d262d1 100644 --- a/rector.php +++ b/rector.php @@ -11,6 +11,8 @@ ->withPaths([ __DIR__ . '/src/Services/Telephony', __DIR__ . '/tests/Integration/Services/Telephony', + __DIR__ . '/src/Services/User', + __DIR__ . '/tests/Integration/Services/User', ]) ->withCache(cacheDirectory: __DIR__ . '.cache/rector') ->withSets( diff --git a/src/Services/User/Result/UserItemResult.php b/src/Services/User/Result/UserItemResult.php index e8ad00e0..de8b597e 100644 --- a/src/Services/User/Result/UserItemResult.php +++ b/src/Services/User/Result/UserItemResult.php @@ -5,8 +5,7 @@ namespace Bitrix24\SDK\Services\User\Result; use Bitrix24\SDK\Core\Result\AbstractItem; -use DateTime; -use DateTimeImmutable; +use Carbon\CarbonImmutable; /** * @property-read int $ID @@ -17,8 +16,8 @@ * @property-read string $SECOND_NAME * @property-read string $TITLE * @property-read string $EMAIL - * @property-read DateTime $LAST_LOGIN - * @property-read DateTime $DATE_REGISTER + * @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 @@ -26,12 +25,12 @@ * @property-read array $LAST_ACTIVITY_DATE * @property-read string $PERSONAL_GENDER * @property-read string $PERSONAL_WWW - * @property-read DateTimeImmutable $PERSONAL_BIRTHDAY + * @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 DateTimeImmutable $UF_EMPLOYMENT_DATE + * @property-read CarbonImmutable $UF_EMPLOYMENT_DATE * @property-read string $UF_TIMEMAN * @property-read array $UF_DEPARTMENT * @property-read string $UF_PHONE_INNER @@ -42,14 +41,17 @@ 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 DateTimeImmutable::createFromFormat(DATE_ATOM, $this->data[$offset]); + return CarbonImmutable::createFromFormat(DATE_ATOM, $this->data[$offset]); } + break; case 'IS_ONLINE': return $this->data[$offset] === 'Y'; diff --git a/src/Services/User/Service/User.php b/src/Services/User/Service/User.php index 80228317..04456e9d 100644 --- a/src/Services/User/Service/User.php +++ b/src/Services/User/Service/User.php @@ -18,7 +18,6 @@ class User extends AbstractService { /** * Get user entity fields - * @return FieldsResult * @throws BaseException * @throws TransportException * @link https://training.bitrix24.com/rest_help/users/user_fields.php @@ -30,7 +29,6 @@ public function fields(): FieldsResult /** * Get current user - * @return UserResult * @throws BaseException * @throws TransportException * @link https://training.bitrix24.com/rest_help/users/user_current.php @@ -44,8 +42,6 @@ public function current(): UserResult * 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'] - * @param string $messageText - * @return AddedItemResult * @throws BaseException * @throws TransportException * @link https://training.bitrix24.com/rest_help/users/user_add.php @@ -53,7 +49,7 @@ public function current(): UserResult public function add(array $fields, string $messageText = ''): AddedItemResult { if (!array_key_exists('EXTRANET', $fields)) { - throw new InvalidArgumentException(sprintf('field EXTRANET is required')); + throw new InvalidArgumentException('field EXTRANET is required'); } return new AddedItemResult($this->core->call( @@ -68,10 +64,7 @@ public function add(array $fields, string $messageText = ''): AddedItemResult } /** - * @param array $order * @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'] - * @param bool $isAdminMode - * @return UsersResult * @throws BaseException * @throws TransportException */ @@ -87,9 +80,6 @@ public function get(array $order, array $filter, bool $isAdminMode = false): Use /** * Updates user information. Available only for users with invitation permissions. - * @param int $userId - * @param array $fields - * @return UpdatedItemResult * @throws BaseException * @throws TransportException * @link https://training.bitrix24.com/rest_help/users/user_update.php @@ -107,8 +97,6 @@ public function update(int $userId, array $fields): UpdatedItemResult /** * 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). * - * @param array $filterFields - * @return UsersResult * @throws BaseException * @throws TransportException * @link https://training.bitrix24.com/rest_help/users/user_search.php diff --git a/src/Services/User/UserServiceBuilder.php b/src/Services/User/UserServiceBuilder.php index d6977687..7b69235d 100644 --- a/src/Services/User/UserServiceBuilder.php +++ b/src/Services/User/UserServiceBuilder.php @@ -9,11 +9,6 @@ class UserServiceBuilder extends AbstractServiceBuilder { - /** - * get user service - * - * @return User - */ public function user(): User { if (!isset($this->serviceCache[__METHOD__])) { diff --git a/tests/Integration/Services/User/Service/UserTest.php b/tests/Integration/Services/User/Service/UserTest.php index e8f0ab26..d8120fb9 100644 --- a/tests/Integration/Services/User/Service/UserTest.php +++ b/tests/Integration/Services/User/Service/UserTest.php @@ -11,34 +11,33 @@ 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; /** - * @return void * @throws BaseException * @throws TransportException - * @covers \Bitrix24\SDK\Services\User\Service\User::get - * @testdox test get users with filter */ + #[TestDox('test get users with filter')] public function testUserSearch(): void { - $users = $this->userService->search([ + $usersResult = $this->userService->search([ 'NAME' => 'test', ]); - $this->assertGreaterThanOrEqual(1, $users->getCoreResponse()->getResponseData()->getPagination()->getTotal()); + $this->assertGreaterThanOrEqual(1, $usersResult->getCoreResponse()->getResponseData()->getPagination()->getTotal()); } /** - * @return void * @throws BaseException * @throws TransportException - * @covers \Bitrix24\SDK\Services\User\Service\User::get - * @testdox test get users list with internal phone */ + #[TestDox('test get users list with internal phone')] public function testGetWithInternalPhone(): void { $this->assertGreaterThanOrEqual( @@ -50,12 +49,10 @@ public function testGetWithInternalPhone(): void } /** - * @covers \Bitrix24\SDK\Services\User\Service\User::get - * @testdox test get users list - * @return void * @throws BaseException * @throws TransportException */ + #[TestDox('test get users list')] public function testGet(): void { $this->assertGreaterThanOrEqual( @@ -64,6 +61,13 @@ public function testGet(): void ); } + #[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 = [ @@ -83,12 +87,10 @@ public function testUpdate(): void } /** - * @covers \Bitrix24\SDK\Services\User\Service\User::add - * @testdox test add user - * @return void * @throws BaseException * @throws TransportException */ + #[TestDox('test add user')] public function testAdd(): void { $newUser = [ @@ -102,30 +104,26 @@ public function testAdd(): void } /** - * @covers \Bitrix24\SDK\Services\User\Service\User::current - * @testdox test get current user - * @return void * @throws BaseException * @throws TransportException */ + #[TestDox('test get current user')] public function testUserCurrent(): void { $this->assertInstanceOf(UserItemResult::class, $this->userService->current()->user()); } /** - * @covers \Bitrix24\SDK\Services\User\Service\User::fields - * @testdox test get user fields - * @return void * @throws BaseException * @throws TransportException */ + #[TestDox('test get user fields')] public function testGetUserFields(): void { $this->assertIsArray($this->userService->fields()->getFieldsDescription()); } - public function setUp(): void + protected function setUp(): void { $this->userService = Fabric::getServiceBuilder()->getUserScope()->user(); } From 5f37207609b278f4c52b27ae2c3023a97be774e9 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 30 Jun 2024 00:48:55 +0600 Subject: [PATCH 065/138] Add default arguments handling in User.get method A check has been added in User.get method, to set a default argument as ascending order of IDs when no explicit order is provided. A corresponding test case 'test get users list with default arguments' has also been included to validate the functionality. The CHAGELOG.md is updated to reflect this fix. Signed-off-by: mesilov --- CHANGELOG.md | 1 + src/Services/User/Service/User.php | 4 ++++ tests/Integration/Services/User/Service/UserTest.php | 6 ++++++ 3 files changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6115ddc..14fd95e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -128,6 +128,7 @@ ### 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) ## 2.0-beta.2 — 1.04.2024 diff --git a/src/Services/User/Service/User.php b/src/Services/User/Service/User.php index 04456e9d..1590a7db 100644 --- a/src/Services/User/Service/User.php +++ b/src/Services/User/Service/User.php @@ -70,6 +70,10 @@ public function add(array $fields, string $messageText = ''): AddedItemResult */ 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], diff --git a/tests/Integration/Services/User/Service/UserTest.php b/tests/Integration/Services/User/Service/UserTest.php index d8120fb9..8e9931fe 100644 --- a/tests/Integration/Services/User/Service/UserTest.php +++ b/tests/Integration/Services/User/Service/UserTest.php @@ -48,6 +48,12 @@ public function testGetWithInternalPhone(): void ); } + #[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 From 8ba67923715f9081cc9dc317e9f24663335cb5d2 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 30 Jun 2024 02:21:36 +0600 Subject: [PATCH 066/138] Add BatchGetTraversableTest and update CHANGELOG Added a new test file named BatchGetTraversableTest to cover the usage of batch operations for managing contacts. Also updated the CHANGELOG to include the fix regarding the limit argument not working in batch list and read model. Signed-off-by: mesilov --- CHANGELOG.md | 6 +- .../Core/BatchGetTraversableTest.php | 126 ++++++++++++++++++ 2 files changed, 128 insertions(+), 4 deletions(-) create mode 100644 tests/Integration/Core/BatchGetTraversableTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 14fd95e4..bca988bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -129,6 +129,7 @@ * 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 @@ -214,10 +215,7 @@ * 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 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 diff --git a/tests/Integration/Core/BatchGetTraversableTest.php b/tests/Integration/Core/BatchGetTraversableTest.php new file mode 100644 index 00000000..92e0c4e4 --- /dev/null +++ b/tests/Integration/Core/BatchGetTraversableTest.php @@ -0,0 +1,126 @@ +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); + } + + + /** + * @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 From f739ac3c25f62a8cca8e34c20ee2f45cfe97ed3e Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 30 Jun 2024 12:15:12 +0600 Subject: [PATCH 067/138] Add Core directory to Rector paths A new path to the Core directory was added to the Rector configuration. This ensures that our Rector tool can identify and manage code within this new directory. Signed-off-by: mesilov --- rector.php | 1 + 1 file changed, 1 insertion(+) diff --git a/rector.php b/rector.php index d4d262d1..87d3e575 100644 --- a/rector.php +++ b/rector.php @@ -9,6 +9,7 @@ return RectorConfig::configure() ->withPaths([ + __DIR__ . '/src/Core/', __DIR__ . '/src/Services/Telephony', __DIR__ . '/tests/Integration/Services/Telephony', __DIR__ . '/src/Services/User', From 0d3537a19cf9a927cce40888bcdcf17a9132dd16 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 30 Jun 2024 12:22:48 +0600 Subject: [PATCH 068/138] Refactor code for better clarity and efficiency In this commit, code clarity and efficiency have been improved across several classes. Unnecessary comments and excessive lines of code have been removed. Additionally, all the constructors and property assignments have been updated to use PHP 7.4 syntax, which provides a more concise way to declare and initialize class properties. In some places, the error messages have been updated to be more descriptive. Finally, the conditionals and the loop iterations have been optimized for better performance. Signed-off-by: mesilov --- src/Core/ApiClient.php | 46 +++---- src/Core/ApiLevelErrorHandler.php | 13 +- src/Core/Batch.php | 122 ++++++++---------- src/Core/BulkItemsReader/BulkItemsReader.php | 17 +-- .../BulkItemsReaderBuilder.php | 28 +--- .../FilterWithBatchWithoutCountOrder.php | 17 +-- .../FilterWithoutBatchWithoutCountOrder.php | 34 +---- src/Core/Commands/Command.php | 38 +----- .../Contracts/AddedItemIdResultInterface.php | 2 - src/Core/Contracts/ApiClientInterface.php | 8 -- .../Contracts/BatchOperationsInterface.php | 12 -- .../Contracts/BulkItemsReaderInterface.php | 1 - src/Core/Contracts/CoreInterface.php | 7 - .../Contracts/DeletedItemResultInterface.php | 2 - .../Contracts/UpdatedItemResultInterface.php | 2 - src/Core/Core.php | 30 +---- src/Core/CoreBuilder.php | 20 +-- src/Core/Credentials/AccessToken.php | 32 +---- src/Core/Credentials/ApplicationProfile.php | 27 +--- src/Core/Credentials/Credentials.php | 66 +++------- src/Core/Credentials/Endpoints.php | 1 + src/Core/Credentials/Scope.php | 7 - src/Core/Credentials/WebhookUrl.php | 6 +- .../MethodConfirmWaitingException.php | 7 +- src/Core/Result/AbstractItem.php | 15 +-- src/Core/Result/AbstractResult.php | 10 +- src/Core/Result/AddedItemBatchResult.php | 11 +- src/Core/Result/AddedItemResult.php | 1 - src/Core/Result/DeletedItemBatchResult.php | 14 +- src/Core/Result/DeletedItemResult.php | 1 - src/Core/Result/FieldsResult.php | 1 - src/Core/Result/UpdatedItemBatchResult.php | 14 +- src/Core/Result/UpdatedItemResult.php | 1 - .../Result/UserInterfaceDialogCallResult.php | 1 - 34 files changed, 147 insertions(+), 467 deletions(-) diff --git a/src/Core/ApiClient.php b/src/Core/ApiClient.php index 4bddc374..289589fd 100644 --- a/src/Core/ApiClient.php +++ b/src/Core/ApiClient.php @@ -18,42 +18,31 @@ class ApiClient implements ApiClientInterface { - protected HttpClientInterface $client; - protected LoggerInterface $logger; - protected Credentials $credentials; - protected RequestIdGeneratorInterface $requestIdGenerator; /** * @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. - * - * @param Credentials $credentials - * @param HttpClientInterface $client - * @param RequestIdGeneratorInterface $requestIdGenerator - * @param LoggerInterface $logger */ public function __construct( - Credentials $credentials, - HttpClientInterface $client, - RequestIdGeneratorInterface $requestIdGenerator, - LoggerInterface $logger) + protected Credentials $credentials, + protected HttpClientInterface $client, + protected RequestIdGeneratorInterface $requestIdGenerator, + protected LoggerInterface $logger) { - $this->credentials = $credentials; - $this->client = $client; - $this->requestIdGenerator = $requestIdGenerator; - $this->logger = $logger; $this->logger->debug( 'ApiClient.init', [ - 'httpClientType' => get_class($client), + 'httpClientType' => $this->client::class, ] ); } @@ -72,16 +61,12 @@ protected function getDefaultHeaders(): array ]; } - /** - * @return Credentials - */ public function getCredentials(): Credentials { return $this->credentials; } /** - * @return RenewedAccessToken * @throws InvalidArgumentException * @throws TransportExceptionInterface * @throws TransportException @@ -92,10 +77,11 @@ public function getNewAccessToken(): RenewedAccessToken $this->logger->debug('getNewAccessToken.start', [ 'requestId' => $requestId ]); - if ($this->getCredentials()->getApplicationProfile() === null) { + if (!$this->getCredentials()->getApplicationProfile() instanceof \Bitrix24\SDK\Core\Credentials\ApplicationProfile) { throw new InvalidArgumentException('application profile not set'); } - if ($this->getCredentials()->getAccessToken() === null) { + + if (!$this->getCredentials()->getAccessToken() instanceof \Bitrix24\SDK\Core\Credentials\AccessToken) { throw new InvalidArgumentException('access token in credentials not set'); } @@ -132,20 +118,20 @@ public function getNewAccessToken(): RenewedAccessToken ]); return $newAccessToken; } + if ($response->getStatusCode() === StatusCodeInterface::STATUS_BAD_REQUEST) { $this->logger->warning('getNewAccessToken.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 string $apiMethod * @param array $parameters * - * @return ResponseInterface * @throws TransportExceptionInterface * @throws InvalidArgumentException */ @@ -163,16 +149,18 @@ public function getResponse(string $apiMethod, array $parameters = []): Response ); $method = 'POST'; - if ($this->getCredentials()->getWebhookUrl() !== null) { + if ($this->getCredentials()->getWebhookUrl() instanceof \Bitrix24\SDK\Core\Credentials\WebhookUrl) { $url = sprintf('%s/%s/', $this->getCredentials()->getWebhookUrl()->getUrl(), $apiMethod); } else { $url = sprintf('%s/rest/%s', $this->getCredentials()->getDomainUrl(), $apiMethod); - if ($this->getCredentials()->getAccessToken() === null) { - throw new InvalidArgumentException(sprintf('access token in credentials not found ')); + if (!$this->getCredentials()->getAccessToken() instanceof \Bitrix24\SDK\Core\Credentials\AccessToken) { + throw new InvalidArgumentException('access token in credentials not found '); } + $parameters['auth'] = $this->getCredentials()->getAccessToken()->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; diff --git a/src/Core/ApiLevelErrorHandler.php b/src/Core/ApiLevelErrorHandler.php index 817c5f63..1ce16ca2 100644 --- a/src/Core/ApiLevelErrorHandler.php +++ b/src/Core/ApiLevelErrorHandler.php @@ -21,20 +21,19 @@ */ class ApiLevelErrorHandler { - protected LoggerInterface $logger; 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. - * - * @param LoggerInterface $logger */ - public function __construct(LoggerInterface $logger) + public function __construct(protected LoggerInterface $logger) { - $this->logger = $logger; } /** @@ -84,14 +83,17 @@ private function handleError(array $responseBody, ?string $batchCommandId = null 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'; } @@ -119,6 +121,7 @@ private function handleError(array $responseBody, ?string $batchCommandId = null default: throw new BaseException(sprintf('%s - %s %s', $errorCode, $errorDescription, $batchErrorPrefix)); } + // switch (strtoupper(trim($apiResponse['error']))) { // case 'EXPIRED_TOKEN': // throw new Bitrix24TokenIsExpiredException($errorMsg); diff --git a/src/Core/Batch.php b/src/Core/Batch.php index 8bb1fa43..fee688bc 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -25,22 +25,17 @@ */ class Batch implements BatchOperationsInterface { - private CoreInterface $core; - private LoggerInterface $logger; protected const MAX_BATCH_PACKET_SIZE = 50; + protected const MAX_ELEMENTS_IN_PAGE = 50; + protected CommandCollection $commands; /** * Batch constructor. - * - * @param CoreInterface $core - * @param LoggerInterface $log */ - public function __construct(CoreInterface $core, LoggerInterface $log) + public function __construct(private readonly CoreInterface $core, private readonly LoggerInterface $logger) { - $this->core = $core; - $this->logger = $log; $this->commands = new CommandCollection(); } @@ -62,7 +57,6 @@ protected function clearCommands(): void /** * Add entity items with batch call * - * @param string $apiMethod * @param array $entityItems * * @return Generator|ResponseData[] @@ -87,16 +81,16 @@ public function addEntityItems(string $apiMethod, array $entityItems): Generator foreach ($this->getTraversable(true) as $cnt => $addedItemResult) { yield $cnt => $addedItemResult; } - } catch (\Throwable $exception) { - $errorMessage = sprintf('batch add entity items: %s', $exception->getMessage()); + } catch (\Throwable $throwable) { + $errorMessage = sprintf('batch add entity items: %s', $throwable->getMessage()); $this->logger->error( $errorMessage, [ - 'trace' => $exception->getTrace(), + 'trace' => $throwable->getTrace(), ] ); - throw new BaseException($errorMessage, $exception->getCode(), $exception); + throw new BaseException($errorMessage, $throwable->getCode(), $throwable); } $this->logger->debug('addEntityItems.finish'); @@ -105,7 +99,6 @@ public function addEntityItems(string $apiMethod, array $entityItems): Generator /** * Delete entity items with batch call * - * @param string $apiMethod * @param array $entityItemId * * @return Generator|ResponseData[] @@ -134,6 +127,7 @@ public function deleteEntityItems(string $apiMethod, array $entityItemId): Gener ) ); } + $this->registerCommand($apiMethod, ['ID' => $itemId]); } @@ -173,7 +167,6 @@ public function deleteEntityItems(string $apiMethod, array $entityItemId): Gener * 'params' => [] // optional fields * ] * - * @param string $apiMethod * @param array> $entityItems * * @return Generator|ResponseData[] @@ -201,6 +194,7 @@ public function updateEntityItems(string $apiMethod, array $entityItems): Genera ) ); } + if (!array_key_exists('fields', $entityItem)) { throw new InvalidArgumentException( sprintf('array key «fields» not found in entity item with id %s', $entityItemId) @@ -214,6 +208,7 @@ public function updateEntityItems(string $apiMethod, array $entityItems): Genera if (array_key_exists('params', $entityItem)) { $cmdArguments['params'] = $entityItem['params']; } + $this->registerCommand($apiMethod, $cmdArguments); } @@ -247,9 +242,7 @@ public function updateEntityItems(string $apiMethod, array $entityItems): Genera /** * Register api command to command collection for batch calls * - * @param string $apiMethod * @param array $parameters - * @param string|null $commandName * @param callable|null $callback not implemented * * @throws \Exception @@ -300,11 +293,8 @@ protected function getReverseOrder(array $order): array } else { $order = array_change_key_case($order, CASE_UPPER); $oldDirection = array_values($order)[0]; - if ($oldDirection === 'ASC') { - $newOrderDirection = 'DESC'; - } else { - $newOrderDirection = 'ASC'; - } + $newOrderDirection = $oldDirection === 'ASC' ? 'DESC' : 'ASC'; + $reverseOrder[array_key_first($order)] = $newOrderDirection; } @@ -321,11 +311,9 @@ protected function getReverseOrder(array $order): array /** * Get traversable list without count elements * - * @param string $apiMethod * @param array $order * @param array $filter * @param array $select - * @param int|null $limit * * @return \Generator * @throws \Bitrix24\SDK\Core\Exceptions\BaseException @@ -396,14 +384,11 @@ public function getTraversableList( if (array_key_exists('entityTypeId', $additionalParameters)) { $isCrmItemsInBatch = true; } + $params = array_merge($params, $additionalParameters); } + $keyId = $isCrmItemsInBatch ? 'id' : 'ID'; - if ($isCrmItemsInBatch) { - $keyId = 'id'; - } else { - $keyId = 'ID'; - } $firstResultPage = $this->core->call($apiMethod, $params); $totalElementsCount = $firstResultPage->getResponseData()->getPagination()->getTotal(); $this->logger->debug('getTraversableList.totalElementsCount', [ @@ -412,13 +397,15 @@ public function getTraversableList( // filtered elements count less than or equal one result page(50 elements) $elementsCounter = 0; if ($totalElementsCount <= self::MAX_ELEMENTS_IN_PAGE) { - foreach ($firstResultPage->getResponseData()->getResult() as $cnt => $listElement) { - $elementsCounter++; + foreach ($firstResultPage->getResponseData()->getResult() as $listElement) { + ++$elementsCounter; if ($limit !== null && $elementsCounter > $limit) { return; } + yield $listElement; } + $this->logger->debug('getTraversableList.finish'); return; @@ -428,21 +415,23 @@ public function getTraversableList( // return first page $lastElementIdInFirstPage = null; if ($isCrmItemsInBatch) { - foreach ($firstResultPage->getResponseData()->getResult()['items'] as $cnt => $listElement) { - $elementsCounter++; + foreach ($firstResultPage->getResponseData()->getResult()['items'] as $listElement) { + ++$elementsCounter; $lastElementIdInFirstPage = (int)$listElement[$keyId]; if ($limit !== null && $elementsCounter > $limit) { return; } + yield $listElement; } } else { - foreach ($firstResultPage->getResponseData()->getResult() as $cnt => $listElement) { - $elementsCounter++; + foreach ($firstResultPage->getResponseData()->getResult() as $listElement) { + ++$elementsCounter; $lastElementIdInFirstPage = (int)$listElement[$keyId]; if ($limit !== null && $elementsCounter > $limit) { return; } + yield $listElement; } } @@ -451,6 +440,7 @@ public function getTraversableList( if (!in_array($keyId, $select, true)) { $select[] = $keyId; } + // getLastElementId in filtered result $params = [ 'order' => $this->getReverseOrder($order), @@ -461,18 +451,21 @@ public function getTraversableList( 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, @@ -480,7 +473,7 @@ public function getTraversableList( // register commands with updated filter //more than one page in results - register list commands - $lastElementIdInFirstPage++; + ++$lastElementIdInFirstPage; for ($startId = $lastElementIdInFirstPage; $startId <= $lastElementId; $startId += self::MAX_ELEMENTS_IN_PAGE) { $this->logger->debug('registerCommand.item', [ 'startId' => $startId, @@ -512,6 +505,7 @@ public function getTraversableList( $this->registerCommand($apiMethod, $params); } + $this->logger->debug( 'getTraversableList.commandsRegistered', [ @@ -520,7 +514,6 @@ public function getTraversableList( ); // iterate batch queries, max: 50 results per 50 elements in each result - $elementsCounter = 0; foreach ($this->getTraversable(true) as $queryCnt => $queryResultData) { /** * @var $queryResultData ResponseData @@ -536,32 +529,31 @@ public function getTraversableList( // iterate items in batch query result if ($isCrmItemsInBatch) { - foreach ($queryResultData->getResult()['items'] as $cnt => $listElement) { - $elementsCounter++; + foreach ($queryResultData->getResult()['items'] as $listElement) { + ++$elementsCounter; if ($limit !== null && $elementsCounter > $limit) { return; } + yield $listElement; } } else { - foreach ($queryResultData->getResult() as $cnt => $listElement) { - $elementsCounter++; + foreach ($queryResultData->getResult() as $listElement) { + ++$elementsCounter; if ($limit !== null && $elementsCounter > $limit) { return; } + yield $listElement; } } } + $this->logger->debug('getTraversableList.finish'); } /** - * @param string $keyId - * @param int $startElementId - * @param int $lastElementId - * @param bool $isLastPage * @param array $oldFilter * * @return array @@ -595,11 +587,9 @@ protected function updateFilterForBatch(string $keyId, int $startElementId, int * * work with start item position and elements count * - * @param string $apiMethod * @param array $order * @param array $filter * @param array $select - * @param int|null $limit * * @return Generator * @throws BaseException @@ -631,7 +621,7 @@ public function getTraversableListWithCount( $this->clearCommands(); // get total elements count - $firstResult = $this->core->call( + $response = $this->core->call( $apiMethod, [ 'order' => $order, @@ -641,8 +631,8 @@ public function getTraversableListWithCount( ] ); - $nextItem = $firstResult->getResponseData()->getPagination()->getNextItem(); - $total = $firstResult->getResponseData()->getPagination()->getTotal(); + $nextItem = $response->getResponseData()->getPagination()->getNextItem(); + $total = $response->getResponseData()->getPagination()->getTotal(); $this->logger->debug( 'getTraversableListWithCount.calculateCommandsRange', @@ -704,11 +694,12 @@ public function getTraversableListWithCount( ] ); // iterate items in batch query result - foreach ($queryResultData->getResult() as $cnt => $listElement) { - $elementsCounter++; + foreach ($queryResultData->getResult() as $listElement) { + ++$elementsCounter; if ($limit !== null && $elementsCounter > $limit) { return; } + yield $listElement; } } @@ -717,7 +708,6 @@ public function getTraversableListWithCount( } /** - * @param bool $isHaltOnError * * @return Generator * @throws BaseException @@ -737,7 +727,7 @@ protected function getTraversable(bool $isHaltOnError): Generator ] ); - foreach ($this->getTraversableBatchResults($isHaltOnError) as $batchItem => $batchResult) { + foreach ($this->getTraversableBatchResults($isHaltOnError) as $batchItem => $traversableBatchResult) { /** * @var $batchResult Response */ @@ -745,12 +735,12 @@ protected function getTraversable(bool $isHaltOnError): Generator 'getTraversable.batchResultItem.processStart', [ 'batchItemNumber' => $batchItem, - 'batchApiCommand' => $batchResult->getApiCommand()->getApiMethod(), - 'batchApiCommandUuid' => $batchResult->getApiCommand()->getUuid()->toString(), + 'batchApiCommand' => $traversableBatchResult->getApiCommand()->getApiMethod(), + 'batchApiCommandUuid' => $traversableBatchResult->getApiCommand()->getUuid()->toString(), ] ); // todo try to multiplex requests - $response = $batchResult->getResponseData(); + $response = $traversableBatchResult->getResponseData(); // single queries // todo handle error field @@ -765,6 +755,7 @@ protected function getTraversable(bool $isHaltOnError): Generator if (!is_array($singleQueryResult)) { $singleQueryResult = [$singleQueryResult]; } + if (!array_key_exists($singleQueryKey, $resultQueryTimeItems)) { throw new BaseException(sprintf('query time with key %s not found', $singleQueryKey)); } @@ -785,13 +776,14 @@ protected function getTraversable(bool $isHaltOnError): Generator new Pagination($nextItem, $total) ); } + $this->logger->debug('getTraversable.batchResult.processFinish'); } + $this->logger->debug('getTraversable.finish'); } /** - * @param bool $isHaltOnError * * @return Generator * @throws BaseException @@ -824,9 +816,10 @@ private function getTraversableBatchResults(bool $isHaltOnError): Generator $batchResult = $this->core->call('batch', ['halt' => $isHaltOnError, 'cmd' => $batchQuery]); // todo analyze batch result and halt on error - $batchQueryCounter++; + ++$batchQueryCounter; yield $batchResult; } + $this->logger->debug('getTraversableBatchResults.finish'); } @@ -836,14 +829,11 @@ private function getTraversableBatchResults(bool $isHaltOnError): Generator private function convertToApiCommands(): array { $apiCommands = []; - foreach ($this->commands as $itemCommand) { - /** - * @var Command $itemCommand - */ - $apiCommands[$itemCommand->getName() ?? $itemCommand->getUuid()->toString()] = sprintf( + foreach ($this->commands as $command) { + $apiCommands[$command->getName() ?? $command->getUuid()->toString()] = sprintf( '%s?%s', - $itemCommand->getApiMethod(), - http_build_query($itemCommand->getParameters()) + $command->getApiMethod(), + http_build_query($command->getParameters()) ); } diff --git a/src/Core/BulkItemsReader/BulkItemsReader.php b/src/Core/BulkItemsReader/BulkItemsReader.php index 50a2809b..fa6f7d7b 100644 --- a/src/Core/BulkItemsReader/BulkItemsReader.php +++ b/src/Core/BulkItemsReader/BulkItemsReader.php @@ -10,27 +10,12 @@ class BulkItemsReader implements BulkItemsReaderInterface { - protected BulkItemsReaderInterface $readStrategy; - protected LoggerInterface $logger; - - /** - * @param \Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface $readStrategy - * @param \Psr\Log\LoggerInterface $logger - */ - public function __construct(BulkItemsReaderInterface $readStrategy, LoggerInterface $logger) + public function __construct(protected BulkItemsReaderInterface $readStrategy, protected LoggerInterface $logger) { - $this->readStrategy = $readStrategy; - $this->logger = $logger; } /** - * @param string $apiMethod - * @param array $order - * @param array $filter - * @param array $select - * @param int|null $limit * - * @return \Generator * @throws \Bitrix24\SDK\Core\Exceptions\BaseException */ public function getTraversableList(string $apiMethod, array $order, array $filter, array $select, ?int $limit = null): Generator diff --git a/src/Core/BulkItemsReader/BulkItemsReaderBuilder.php b/src/Core/BulkItemsReader/BulkItemsReaderBuilder.php index 0c0fa8ea..84da8de9 100644 --- a/src/Core/BulkItemsReader/BulkItemsReaderBuilder.php +++ b/src/Core/BulkItemsReader/BulkItemsReaderBuilder.php @@ -12,49 +12,29 @@ class BulkItemsReaderBuilder { - protected CoreInterface $core; - protected BatchOperationsInterface $batch; - protected LoggerInterface $logger; protected BulkItemsReaderInterface $readStrategy; - /** - * @param \Bitrix24\SDK\Core\Contracts\CoreInterface $core - * @param \Bitrix24\SDK\Core\Contracts\BatchOperationsInterface $batch - * @param \Psr\Log\LoggerInterface $logger - */ - public function __construct(CoreInterface $core, BatchOperationsInterface $batch, LoggerInterface $logger) + public function __construct(protected CoreInterface $core, protected BatchOperationsInterface $batch, protected LoggerInterface $logger) { - $this->core = $core; - $this->batch = $batch; - $this->logger = $logger; $this->readStrategy = $this->getOptimalReadStrategy(); } - /** - * @param \Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface $readStrategy - * - * @return BulkItemsReaderBuilder - */ - public function withReadStrategy(BulkItemsReaderInterface $readStrategy): BulkItemsReaderBuilder + + public function withReadStrategy(BulkItemsReaderInterface $bulkItemsReader): BulkItemsReaderBuilder { - $this->readStrategy = $readStrategy; + $this->readStrategy = $bulkItemsReader; return $this; } /** * Get optimal read strategy based on integration tests with time and performance benchmarks - * - * @return \Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface */ protected function getOptimalReadStrategy(): BulkItemsReaderInterface { return new FilterWithBatchWithoutCountOrder($this->batch, $this->logger); } - /** - * @return \Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface - */ public function build(): BulkItemsReaderInterface { return new BulkItemsReader($this->readStrategy, $this->logger); diff --git a/src/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrder.php b/src/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrder.php index b8eed12d..cfe7f243 100644 --- a/src/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrder.php +++ b/src/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrder.php @@ -11,27 +11,12 @@ class FilterWithBatchWithoutCountOrder implements BulkItemsReaderInterface { - private BatchOperationsInterface $batch; - private LoggerInterface $log; - - /** - * @param \Bitrix24\SDK\Core\Contracts\BatchOperationsInterface $batch - * @param \Psr\Log\LoggerInterface $log - */ - public function __construct(BatchOperationsInterface $batch, LoggerInterface $log) + public function __construct(private readonly BatchOperationsInterface $batch, private readonly LoggerInterface $log) { - $this->batch = $batch; - $this->log = $log; } /** - * @param string $apiMethod - * @param array $order - * @param array $filter - * @param array $select - * @param int|null $limit * - * @return \Generator * @throws \Bitrix24\SDK\Core\Exceptions\BaseException * @throws \Bitrix24\SDK\Core\Exceptions\TransportException */ diff --git a/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php b/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php index e1d6c8c8..cdcf43d0 100644 --- a/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php +++ b/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php @@ -11,27 +11,12 @@ class FilterWithoutBatchWithoutCountOrder implements BulkItemsReaderInterface { - private CoreInterface $core; - private LoggerInterface $log; - - /** - * @param \Bitrix24\SDK\Core\Contracts\CoreInterface $core - * @param \Psr\Log\LoggerInterface $log - */ - public function __construct(CoreInterface $core, LoggerInterface $log) + public function __construct(private readonly CoreInterface $core, private readonly LoggerInterface $log) { - $this->core = $core; - $this->log = $log; } /** - * @param string $apiMethod - * @param array $order - * @param array $filter - * @param array $select - * @param int|null $limit * - * @return \Generator * @throws \Bitrix24\SDK\Core\Exceptions\BaseException * @throws \Bitrix24\SDK\Core\Exceptions\TransportException */ @@ -87,6 +72,7 @@ public function getTraversableList(string $apiMethod, array $order, array $filte return; } + $lastElementId = $this->getLastElementId($apiMethod, $filter, $select); if ($lastElementId === null) { $this->log->debug('FilterWithoutBatchWithoutCountOrder.getTraversableList.emptySelect'); @@ -140,11 +126,7 @@ public function getTraversableList(string $apiMethod, array $order, array $filte /** * Get first element id in filtered result ordered by id asc * - * @param string $apiMethod - * @param array $filter - * @param array $select * - * @return int|null * @throws \Bitrix24\SDK\Core\Exceptions\BaseException * @throws \Bitrix24\SDK\Core\Exceptions\TransportException * @todo Кандидат на вынос @@ -157,7 +139,7 @@ private function getFirstElementId(string $apiMethod, array $filter, array $sele 'select' => $select, ]); - $firstResultPage = $this->core->call( + $response = $this->core->call( $apiMethod, [ 'order' => ['ID' => 'ASC'], @@ -167,7 +149,7 @@ private function getFirstElementId(string $apiMethod, array $filter, array $sele ] ); - $elementId = $firstResultPage->getResponseData()->getResult()[0]['ID']; + $elementId = $response->getResponseData()->getResult()[0]['ID']; $this->log->debug('FilterWithoutBatchWithoutCountOrder.getFirstElementId.finish', [ 'elementId' => $elementId, @@ -179,11 +161,7 @@ private function getFirstElementId(string $apiMethod, array $filter, array $sele /** * Get first element id in filtered result ordered by id asc * - * @param string $apiMethod - * @param array $filter - * @param array $select * - * @return int|null * @throws \Bitrix24\SDK\Core\Exceptions\BaseException * @throws \Bitrix24\SDK\Core\Exceptions\TransportException * @todo Кандидат на вынос @@ -196,7 +174,7 @@ private function getLastElementId(string $apiMethod, array $filter, array $selec 'select' => $select, ]); - $lastResultPage = $this->core->call( + $response = $this->core->call( $apiMethod, [ 'order' => ['ID' => 'DESC'], @@ -206,7 +184,7 @@ private function getLastElementId(string $apiMethod, array $filter, array $selec ] ); - $elementId = $lastResultPage->getResponseData()->getResult()[0]['ID']; + $elementId = $response->getResponseData()->getResult()[0]['ID']; $this->log->debug('FilterWithoutBatchWithoutCountOrder.getLastElementId.finish', [ 'elementId' => $elementId, diff --git a/src/Core/Commands/Command.php b/src/Core/Commands/Command.php index 471bb9dd..a4a6e37e 100644 --- a/src/Core/Commands/Command.php +++ b/src/Core/Commands/Command.php @@ -14,67 +14,37 @@ */ class Command { - /** - * @var string - */ - private $apiMethod; - /** - * @var array - */ - private $parameters; - /** - * @var null|string - */ - private $name; - /** - * @var UuidInterface - */ - private $uuid; + private readonly string $name; + + private readonly \Ramsey\Uuid\UuidInterface $uuid; /** * BatchCommand constructor. * - * @param string $apiMethod - * @param array $parameters - * @param string|null $name * * @throws \Exception */ - public function __construct(string $apiMethod, array $parameters, ?string $name = null) + public function __construct(private readonly string $apiMethod, private readonly array $parameters, ?string $name = null) { $this->uuid = Uuid::uuid4(); - $this->apiMethod = $apiMethod; - $this->parameters = $parameters; $this->name = $name ?? $this->uuid->toString(); } - /** - * @return UuidInterface - */ public function getUuid(): UuidInterface { return $this->uuid; } - /** - * @return string - */ public function getApiMethod(): string { return $this->apiMethod; } - /** - * @return array - */ public function getParameters(): array { return $this->parameters; } - /** - * @return string|null - */ public function getName(): ?string { return $this->name; diff --git a/src/Core/Contracts/AddedItemIdResultInterface.php b/src/Core/Contracts/AddedItemIdResultInterface.php index e9adcf78..465bd43c 100644 --- a/src/Core/Contracts/AddedItemIdResultInterface.php +++ b/src/Core/Contracts/AddedItemIdResultInterface.php @@ -8,8 +8,6 @@ interface AddedItemIdResultInterface { /** * added entity id - * - * @return int */ public function getId(): int; } \ No newline at end of file diff --git a/src/Core/Contracts/ApiClientInterface.php b/src/Core/Contracts/ApiClientInterface.php index f4782170..11903492 100644 --- a/src/Core/Contracts/ApiClientInterface.php +++ b/src/Core/Contracts/ApiClientInterface.php @@ -13,24 +13,16 @@ interface ApiClientInterface { /** - * @param string $apiMethod - * @param array $parameters - * - * @return ResponseInterface * @throws TransportExceptionInterface * @throws InvalidArgumentException */ public function getResponse(string $apiMethod, array $parameters = []): ResponseInterface; /** - * @return RenewedAccessToken * @throws InvalidArgumentException * @throws TransportExceptionInterface */ public function getNewAccessToken(): RenewedAccessToken; - /** - * @return Credentials - */ public function getCredentials(): Credentials; } \ No newline at end of file diff --git a/src/Core/Contracts/BatchOperationsInterface.php b/src/Core/Contracts/BatchOperationsInterface.php index f6e5b55c..e11c804b 100644 --- a/src/Core/Contracts/BatchOperationsInterface.php +++ b/src/Core/Contracts/BatchOperationsInterface.php @@ -18,12 +18,9 @@ interface BatchOperationsInterface /** * Batch wrapper for *.list methods without counting elements on every api-call * - * @param string $apiMethod * @param array $order * @param array $filter * @param array $select - * @param int|null $limit - * @param array|null $additionalParameters * @return Generator * @throws BaseException */ @@ -41,13 +38,7 @@ public function getTraversableList( * * ⚠️ Call this wrapper is more expensive than getTraversableList method, use this method carefully * - * @param string $apiMethod - * @param array $order - * @param array $filter - * @param array $select - * @param int|null $limit * - * @return Generator * @throws BaseException */ public function getTraversableListWithCount( @@ -61,7 +52,6 @@ public function getTraversableListWithCount( /** * Add entity items with batch call * - * @param string $apiMethod * @param array $entityItems * * @return Generator|ResponseData[] @@ -72,7 +62,6 @@ public function addEntityItems(string $apiMethod, array $entityItems): Generator /** * Delete entity items with batch call * - * @param string $apiMethod * @param array $entityItemId * * @return Generator|ResponseData[] @@ -83,7 +72,6 @@ public function deleteEntityItems(string $apiMethod, array $entityItemId): Gener /** * Update entity items with batch call * - * @param string $apiMethod * @param array $entityItems * * @return Generator|ResponseData[] diff --git a/src/Core/Contracts/BulkItemsReaderInterface.php b/src/Core/Contracts/BulkItemsReaderInterface.php index 515dcb55..9c3ee383 100644 --- a/src/Core/Contracts/BulkItemsReaderInterface.php +++ b/src/Core/Contracts/BulkItemsReaderInterface.php @@ -20,7 +20,6 @@ interface BulkItemsReaderInterface * @param array $select select element fields * @param int|null $limit limit elements or read all elements * - * @return Generator * @throws BaseException */ public function getTraversableList(string $apiMethod, array $order, array $filter, array $select, ?int $limit = null): Generator; diff --git a/src/Core/Contracts/CoreInterface.php b/src/Core/Contracts/CoreInterface.php index 85fa6201..d58ccf33 100644 --- a/src/Core/Contracts/CoreInterface.php +++ b/src/Core/Contracts/CoreInterface.php @@ -16,17 +16,10 @@ interface CoreInterface { /** - * @param string $apiMethod - * @param array $parameters - * - * @return Response * @throws BaseException * @throws TransportException */ public function call(string $apiMethod, array $parameters = []): Response; - /** - * @return \Bitrix24\SDK\Core\Contracts\ApiClientInterface - */ public function getApiClient(): ApiClientInterface; } \ No newline at end of file diff --git a/src/Core/Contracts/DeletedItemResultInterface.php b/src/Core/Contracts/DeletedItemResultInterface.php index 8241f02e..053bf8c7 100644 --- a/src/Core/Contracts/DeletedItemResultInterface.php +++ b/src/Core/Contracts/DeletedItemResultInterface.php @@ -8,8 +8,6 @@ interface DeletedItemResultInterface { /** * Success deletion flag - * - * @return bool */ public function isSuccess(): bool; } \ No newline at end of file diff --git a/src/Core/Contracts/UpdatedItemResultInterface.php b/src/Core/Contracts/UpdatedItemResultInterface.php index a1dda726..7e95eda2 100644 --- a/src/Core/Contracts/UpdatedItemResultInterface.php +++ b/src/Core/Contracts/UpdatedItemResultInterface.php @@ -8,8 +8,6 @@ interface UpdatedItemResultInterface { /** * Success update flag - * - * @return bool */ public function isSuccess(): bool; } \ No newline at end of file diff --git a/src/Core/Core.php b/src/Core/Core.php index a1a473f9..3b533680 100644 --- a/src/Core/Core.php +++ b/src/Core/Core.php @@ -26,37 +26,14 @@ */ class Core implements CoreInterface { - protected ApiClientInterface $apiClient; - protected LoggerInterface $logger; - protected EventDispatcherInterface $eventDispatcher; - protected ApiLevelErrorHandler $apiLevelErrorHandler; - /** * Main constructor. - * - * @param ApiClientInterface $apiClient - * @param ApiLevelErrorHandler $apiLevelErrorHandler - * @param EventDispatcherInterface $eventDispatcher - * @param LoggerInterface $logger */ - public function __construct( - ApiClientInterface $apiClient, - ApiLevelErrorHandler $apiLevelErrorHandler, - EventDispatcherInterface $eventDispatcher, - LoggerInterface $logger - ) + public function __construct(protected ApiClientInterface $apiClient, protected ApiLevelErrorHandler $apiLevelErrorHandler, protected EventDispatcherInterface $eventDispatcher, protected LoggerInterface $logger) { - $this->apiClient = $apiClient; - $this->apiLevelErrorHandler = $apiLevelErrorHandler; - $this->eventDispatcher = $eventDispatcher; - $this->logger = $logger; } /** - * @param string $apiMethod - * @param array $parameters - * - * @return Response * @throws BaseException * @throws TransportException */ @@ -163,6 +140,7 @@ public function call(string $apiMethod, array $parameters = []): Response default: throw new BaseException('UNAUTHORIZED request error'); } + break; case StatusCodeInterface::STATUS_FORBIDDEN: $body = $apiCallResponse->toArray(false); @@ -221,14 +199,12 @@ public function call(string $apiMethod, array $parameters = []): Response ); throw new BaseException(sprintf('unknown error - %s', $exception->getMessage()), $exception->getCode(), $exception); } + $this->logger->debug('call.finish'); return $response; } - /** - * @return \Bitrix24\SDK\Core\Contracts\ApiClientInterface - */ public function getApiClient(): ApiClientInterface { return $this->apiClient; diff --git a/src/Core/CoreBuilder.php b/src/Core/CoreBuilder.php index 8f0d7960..96572cc1 100644 --- a/src/Core/CoreBuilder.php +++ b/src/Core/CoreBuilder.php @@ -25,12 +25,18 @@ */ class CoreBuilder { - private ?ApiClientInterface $apiClient; + private ?ApiClientInterface $apiClient = null; + private HttpClientInterface $httpClient; + private EventDispatcherInterface $eventDispatcher; + private LoggerInterface $logger; - private ?Credentials $credentials; - private ApiLevelErrorHandler $apiLevelErrorHandler; + + private ?Credentials $credentials = null; + + private readonly ApiLevelErrorHandler $apiLevelErrorHandler; + private RequestIdGeneratorInterface $requestIdGenerator; /** @@ -46,8 +52,6 @@ public function __construct() 'timeout' => 120, ] ); - $this->credentials = null; - $this->apiClient = null; $this->apiLevelErrorHandler = new ApiLevelErrorHandler($this->logger); $this->requestIdGenerator = new DefaultRequestIdGenerator(); } @@ -58,8 +62,6 @@ public function withRequestIdGenerator(RequestIdGeneratorInterface $requestIdGen } /** - * @param Credentials $credentials - * * @return $this */ public function withCredentials(Credentials $credentials): self @@ -102,11 +104,11 @@ public function withEventDispatcher(EventDispatcherInterface $eventDispatcher): */ public function build(): CoreInterface { - if ($this->credentials === null) { + if (!$this->credentials instanceof \Bitrix24\SDK\Core\Credentials\Credentials) { throw new InvalidArgumentException('you must set credentials before call method build'); } - if ($this->apiClient === null) { + if (!$this->apiClient instanceof \Bitrix24\SDK\Core\Contracts\ApiClientInterface) { $this->apiClient = new ApiClient( $this->credentials, $this->httpClient, diff --git a/src/Core/Credentials/AccessToken.php b/src/Core/Credentials/AccessToken.php index 54e26478..ebb02d3c 100644 --- a/src/Core/Credentials/AccessToken.php +++ b/src/Core/Credentials/AccessToken.php @@ -10,33 +10,17 @@ class AccessToken { - protected string $accessToken; - protected ?string $refreshToken; - protected int $expires; - protected ?int $expiresIn; - /** * AccessToken constructor. - * - * @param string $accessToken - * @param string|null $refreshToken - * @param int $expires - * @param int|null $expiresIn */ - public function __construct(string $accessToken, ?string $refreshToken, int $expires, ?int $expiresIn = null) + public function __construct(protected string $accessToken, protected ?string $refreshToken, protected int $expires, protected ?int $expiresIn = null) { - $this->accessToken = $accessToken; - $this->refreshToken = $refreshToken; - $this->expires = $expires; - $this->expiresIn = $expiresIn; } /** * Is this one-off token from event * * One-off tokens do not have refresh token field - * - * @return bool */ public function isOneOff(): bool { @@ -53,27 +37,17 @@ public function getRefreshToken(): ?string return $this->refreshToken; } - /** - * @return int - */ public function getExpires(): int { return $this->expires; } - /** - * @return bool - */ public function hasExpired(): bool { return $this->getExpires() <= time(); } - /** - * @param array $request - * - * @return self - */ + public static function initFromArray(array $request): self { return new self( @@ -109,9 +83,11 @@ public static function initFromPlacementRequest(HttpFoundation\Request $request) 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'); } diff --git a/src/Core/Credentials/ApplicationProfile.php b/src/Core/Credentials/ApplicationProfile.php index 9b8816da..dbad55ab 100644 --- a/src/Core/Credentials/ApplicationProfile.php +++ b/src/Core/Credentials/ApplicationProfile.php @@ -14,45 +14,28 @@ 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'; - private string $clientId; - private string $clientSecret; - private Scope $scope; /** * ApplicationProfile constructor. - * - * @param string $clientId - * @param string $clientSecret - * @param Scope $scope */ - public function __construct(string $clientId, string $clientSecret, Scope $scope) + public function __construct(private readonly string $clientId, private readonly string $clientSecret, private readonly Scope $scope) { - $this->clientId = $clientId; - $this->clientSecret = $clientSecret; - $this->scope = $scope; } - /** - * @return string - */ public function getClientId(): string { return $this->clientId; } - /** - * @return string - */ public function getClientSecret(): string { return $this->clientSecret; } - /** - * @return Scope - */ public function getScope(): Scope { return $this->scope; @@ -66,9 +49,11 @@ 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)); } @@ -76,7 +61,7 @@ public static function initFromArray(array $appProfile): self return new self( $appProfile[self::BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID], $appProfile[self::BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET], - new Scope(str_replace(' ', '', explode(',', $appProfile[self::BITRIX24_PHP_SDK_APPLICATION_SCOPE]))), + 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/Credentials.php b/src/Core/Credentials/Credentials.php index 476bfc38..a174a010 100644 --- a/src/Core/Credentials/Credentials.php +++ b/src/Core/Credentials/Credentials.php @@ -9,47 +9,38 @@ class Credentials { - protected ?WebhookUrl $webhookUrl; - protected ?AccessToken $accessToken; - protected ?ApplicationProfile $applicationProfile; - protected ?string $domainUrl; + protected ?string $domainUrl = null; /** * Credentials constructor. * - * @param WebhookUrl|null $webhookUrl - * @param AccessToken|null $accessToken - * @param ApplicationProfile|null $applicationProfile - * @param string|null $domainUrl * * @throws InvalidArgumentException */ public function __construct( - ?WebhookUrl $webhookUrl, - ?AccessToken $accessToken, - ?ApplicationProfile $applicationProfile, + protected ?WebhookUrl $webhookUrl, + protected ?AccessToken $accessToken, + protected ?ApplicationProfile $applicationProfile, ?string $domainUrl ) { - $this->webhookUrl = $webhookUrl; - $this->accessToken = $accessToken; - $this->applicationProfile = $applicationProfile; - if ($domainUrl !== null) { $this->setDomainUrl($domainUrl); } - if ($this->accessToken === null && $this->webhookUrl === null) { + if (!$this->accessToken instanceof \Bitrix24\SDK\Core\Credentials\AccessToken && !$this->webhookUrl instanceof \Bitrix24\SDK\Core\Credentials\WebhookUrl) { throw new \LogicException('you must set on of auth type: webhook or OAuth 2.0'); } - if ($this->accessToken !== null && $this->domainUrl === null) { - throw new \LogicException('for oauth type you must set domain url'); + + if (!$this->accessToken instanceof \Bitrix24\SDK\Core\Credentials\AccessToken) { + return; } + if ($this->domainUrl !== null) { + return; + } + throw new \LogicException('for oauth type you must set domain url'); } - /** - * @param AccessToken $accessToken - */ public function setAccessToken(AccessToken $accessToken): void { $this->accessToken = $accessToken; @@ -58,9 +49,7 @@ public function setAccessToken(AccessToken $accessToken): void /** * Set domain url * - * @param string $domainUrl * - * @return void * @throws InvalidArgumentException */ public function setDomainUrl(string $domainUrl): void @@ -73,56 +62,38 @@ public function setDomainUrl(string $domainUrl): void 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 !== null && $this->accessToken === null; + return $this->webhookUrl instanceof \Bitrix24\SDK\Core\Credentials\WebhookUrl && !$this->accessToken instanceof \Bitrix24\SDK\Core\Credentials\AccessToken; } - /** - * @return ApplicationProfile|null - */ public function getApplicationProfile(): ?ApplicationProfile { return $this->applicationProfile; } - /** - * @return string - */ public function getDomainUrl(): string { - if ($this->getWebhookUrl() !== null) { - $arUrl = parse_url($this->getWebhookUrl()->getUrl()); - } else { - $arUrl = parse_url($this->domainUrl); - } + $arUrl = $this->getWebhookUrl() instanceof \Bitrix24\SDK\Core\Credentials\WebhookUrl ? parse_url($this->getWebhookUrl()->getUrl()) : parse_url((string) $this->domainUrl); return sprintf('%s://%s', $arUrl['scheme'], $arUrl['host']); } - /** - * @return WebhookUrl|null - */ public function getWebhookUrl(): ?WebhookUrl { return $this->webhookUrl; } - /** - * @return AccessToken|null - */ public function getAccessToken(): ?AccessToken { return $this->accessToken; } /** - * @param WebhookUrl $webhookUrl - * - * @return self * @throws InvalidArgumentException */ public static function createFromWebhook(WebhookUrl $webhookUrl): self @@ -136,11 +107,7 @@ public static function createFromWebhook(WebhookUrl $webhookUrl): self } /** - * @param AccessToken $accessToken - * @param ApplicationProfile $applicationProfile - * @param string $domainUrl * - * @return self * @throws InvalidArgumentException */ public static function createFromOAuth(AccessToken $accessToken, ApplicationProfile $applicationProfile, string $domainUrl): self @@ -154,10 +121,7 @@ public static function createFromOAuth(AccessToken $accessToken, ApplicationProf } /** - * @param \Bitrix24\SDK\Application\Requests\Placement\PlacementRequest $placementRequest - * @param \Bitrix24\SDK\Core\Credentials\ApplicationProfile $applicationProfile * - * @return self * @throws InvalidArgumentException */ public static function createFromPlacementRequest(PlacementRequest $placementRequest, ApplicationProfile $applicationProfile): self diff --git a/src/Core/Credentials/Endpoints.php b/src/Core/Credentials/Endpoints.php index 9c826eb7..6429ed02 100644 --- a/src/Core/Credentials/Endpoints.php +++ b/src/Core/Credentials/Endpoints.php @@ -23,6 +23,7 @@ public function __construct( 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)); } diff --git a/src/Core/Credentials/Scope.php b/src/Core/Credentials/Scope.php index b353d598..dae5cbb4 100644 --- a/src/Core/Credentials/Scope.php +++ b/src/Core/Credentials/Scope.php @@ -73,15 +73,11 @@ class Scope 'userfieldconfig', ]; - /** - * @var array - */ protected array $currentScope = []; /** * Scope constructor. * - * @param array $scope * * @throws UnknownScopeCodeException */ @@ -102,9 +98,6 @@ public function __construct(array $scope = []) $this->currentScope = $scope; } - /** - * @return array - */ public function getScopeCodes(): array { return $this->currentScope; diff --git a/src/Core/Credentials/WebhookUrl.php b/src/Core/Credentials/WebhookUrl.php index e33cabd0..8d7a8769 100644 --- a/src/Core/Credentials/WebhookUrl.php +++ b/src/Core/Credentials/WebhookUrl.php @@ -16,8 +16,6 @@ class WebhookUrl protected string $url; /** - * @param string $webhookUrl - * * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException */ public function __construct(string $webhookUrl) @@ -25,12 +23,10 @@ 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; } - /** - * @return string - */ public function getUrl(): string { return $this->url; diff --git a/src/Core/Exceptions/MethodConfirmWaitingException.php b/src/Core/Exceptions/MethodConfirmWaitingException.php index 2b282151..94141e00 100644 --- a/src/Core/Exceptions/MethodConfirmWaitingException.php +++ b/src/Core/Exceptions/MethodConfirmWaitingException.php @@ -8,11 +8,8 @@ class MethodConfirmWaitingException extends BaseException { - public readonly string $methodName; - - public function __construct(string $methodName, string $message, int $code = 0, ?Throwable $previous = null) + public function __construct(public readonly string $methodName, string $message, int $code = 0, ?Throwable $throwable = null) { - parent::__construct($message, $code, $previous); - $this->methodName = $methodName; + parent::__construct($message, $code, $throwable); } } \ No newline at end of file diff --git a/src/Core/Result/AbstractItem.php b/src/Core/Result/AbstractItem.php index 5522a869..4d13d439 100644 --- a/src/Core/Result/AbstractItem.php +++ b/src/Core/Result/AbstractItem.php @@ -18,19 +18,15 @@ */ abstract class AbstractItem implements IteratorAggregate { - protected array $data; protected DecimalMoneyParser $decimalMoneyParser; - public function __construct(array $data) + public function __construct(protected array $data) { - $this->data = $data; $this->decimalMoneyParser = new DecimalMoneyParser(new ISOCurrencies()); } /** * @param int|string $offset - * - * @return bool */ public function __isset($offset): bool { @@ -49,13 +45,12 @@ public function __get($offset) /** * @param int|string $offset - * @param mixed $value * * @return void * @throws ImmutableResultViolationException * */ - public function __set($offset, $value) + public function __set($offset, mixed $value) { throw new ImmutableResultViolationException(sprintf('Result is immutable, violation at offset %s', $offset)); } @@ -78,11 +73,7 @@ public function getIterator(): Traversable return new ArrayIterator($this->data); } - /** - * @param string $key - * - * @return bool - */ + protected function isKeyExists(string $key): bool { return array_key_exists($key, $this->data); diff --git a/src/Core/Result/AbstractResult.php b/src/Core/Result/AbstractResult.php index 1eac6f05..b3fae786 100644 --- a/src/Core/Result/AbstractResult.php +++ b/src/Core/Result/AbstractResult.php @@ -13,21 +13,13 @@ */ abstract class AbstractResult { - protected Response $coreResponse; - /** * AbstractResult constructor. - * - * @param Response $coreResponse */ - public function __construct(Response $coreResponse) + public function __construct(protected Response $coreResponse) { - $this->coreResponse = $coreResponse; } - /** - * @return Response - */ public function getCoreResponse(): Response { return $this->coreResponse; diff --git a/src/Core/Result/AddedItemBatchResult.php b/src/Core/Result/AddedItemBatchResult.php index 14180bbe..eb765e6f 100644 --- a/src/Core/Result/AddedItemBatchResult.php +++ b/src/Core/Result/AddedItemBatchResult.php @@ -9,19 +9,10 @@ class AddedItemBatchResult implements AddedItemIdResultInterface { - private ResponseData $responseData; - - /** - * @param \Bitrix24\SDK\Core\Response\DTO\ResponseData $responseData - */ - public function __construct(ResponseData $responseData) + public function __construct(private readonly ResponseData $responseData) { - $this->responseData = $responseData; } - /** - * @return \Bitrix24\SDK\Core\Response\DTO\ResponseData - */ public function getResponseData(): ResponseData { return $this->responseData; diff --git a/src/Core/Result/AddedItemResult.php b/src/Core/Result/AddedItemResult.php index bb491edc..509d0e4d 100644 --- a/src/Core/Result/AddedItemResult.php +++ b/src/Core/Result/AddedItemResult.php @@ -15,7 +15,6 @@ class AddedItemResult extends AbstractResult implements AddedItemIdResultInterface { /** - * @return int * @throws BaseException */ public function getId(): int diff --git a/src/Core/Result/DeletedItemBatchResult.php b/src/Core/Result/DeletedItemBatchResult.php index d63e67ab..1d06b6f6 100644 --- a/src/Core/Result/DeletedItemBatchResult.php +++ b/src/Core/Result/DeletedItemBatchResult.php @@ -9,27 +9,15 @@ class DeletedItemBatchResult implements DeletedItemResultInterface { - private ResponseData $responseData; - - /** - * @param \Bitrix24\SDK\Core\Response\DTO\ResponseData $responseData - */ - public function __construct(ResponseData $responseData) + public function __construct(private readonly ResponseData $responseData) { - $this->responseData = $responseData; } - /** - * @return \Bitrix24\SDK\Core\Response\DTO\ResponseData - */ public function getResponseData(): ResponseData { return $this->responseData; } - /** - * @return bool - */ public function isSuccess(): bool { return (bool)$this->getResponseData()->getResult()[0]; diff --git a/src/Core/Result/DeletedItemResult.php b/src/Core/Result/DeletedItemResult.php index 4eb5b4c4..75f599a2 100644 --- a/src/Core/Result/DeletedItemResult.php +++ b/src/Core/Result/DeletedItemResult.php @@ -15,7 +15,6 @@ class DeletedItemResult extends AbstractResult implements DeletedItemResultInterface { /** - * @return bool * @throws BaseException */ public function isSuccess(): bool diff --git a/src/Core/Result/FieldsResult.php b/src/Core/Result/FieldsResult.php index b9d7b435..d1069c82 100644 --- a/src/Core/Result/FieldsResult.php +++ b/src/Core/Result/FieldsResult.php @@ -14,7 +14,6 @@ class FieldsResult extends AbstractResult { /** - * @return array * @throws BaseException */ public function getFieldsDescription(): array diff --git a/src/Core/Result/UpdatedItemBatchResult.php b/src/Core/Result/UpdatedItemBatchResult.php index e36de654..67250b73 100644 --- a/src/Core/Result/UpdatedItemBatchResult.php +++ b/src/Core/Result/UpdatedItemBatchResult.php @@ -9,27 +9,15 @@ class UpdatedItemBatchResult implements UpdatedItemResultInterface { - private ResponseData $responseData; - - /** - * @param \Bitrix24\SDK\Core\Response\DTO\ResponseData $responseData - */ - public function __construct(ResponseData $responseData) + public function __construct(private readonly ResponseData $responseData) { - $this->responseData = $responseData; } - /** - * @return \Bitrix24\SDK\Core\Response\DTO\ResponseData - */ public function getResponseData(): ResponseData { return $this->responseData; } - /** - * @return bool - */ public function isSuccess(): bool { return (bool)$this->getResponseData()->getResult()[0]; diff --git a/src/Core/Result/UpdatedItemResult.php b/src/Core/Result/UpdatedItemResult.php index 1995f034..0ebd4d07 100644 --- a/src/Core/Result/UpdatedItemResult.php +++ b/src/Core/Result/UpdatedItemResult.php @@ -14,7 +14,6 @@ class UpdatedItemResult extends AbstractResult { /** - * @return bool * @throws BaseException */ public function isSuccess(): bool diff --git a/src/Core/Result/UserInterfaceDialogCallResult.php b/src/Core/Result/UserInterfaceDialogCallResult.php index 1e12f581..35ca3f0d 100644 --- a/src/Core/Result/UserInterfaceDialogCallResult.php +++ b/src/Core/Result/UserInterfaceDialogCallResult.php @@ -9,7 +9,6 @@ class UserInterfaceDialogCallResult extends AbstractResult { /** - * @return bool * @throws BaseException */ public function isSuccess(): bool From 9c6c4fa508a0581f2eb32f8b46419f7dd88fd23e Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 30 Jun 2024 18:35:51 +0600 Subject: [PATCH 069/138] Refactor DTO classes, optimizing methods and properties This commit focuses on restructuring DTO classes to improve readability and efficiency. Specific changes include making classes read-only, reducing unnecessary lines of code and using concise property promotion in the constructor parameters. The refactored classes include Time, ResponseData, Pagination, RenewedAccessToken, and Response. Signed-off-by: mesilov --- src/Core/Response/DTO/Pagination.php | 28 +----- src/Core/Response/DTO/RenewedAccessToken.php | 64 ++----------- src/Core/Response/DTO/ResponseData.php | 30 +----- src/Core/Response/DTO/Time.php | 96 ++++---------------- src/Core/Response/Response.php | 47 +++------- 5 files changed, 44 insertions(+), 221 deletions(-) diff --git a/src/Core/Response/DTO/Pagination.php b/src/Core/Response/DTO/Pagination.php index 3f1816ef..12a7d78e 100644 --- a/src/Core/Response/DTO/Pagination.php +++ b/src/Core/Response/DTO/Pagination.php @@ -4,39 +4,19 @@ namespace Bitrix24\SDK\Core\Response\DTO; -/** - * Class Pagination - * - * @package Bitrix24\SDK\Core\Response\DTO - */ -class Pagination +readonly class Pagination { - private ?int $nextItem; - private ?int $total; - - /** - * Pagination constructor. - * - * @param int|null $nextItem - * @param int|null $total - */ - public function __construct(int $nextItem = null, int $total = null) + public function __construct( + private ?int $nextItem = null, + private ?int $total = null) { - $this->nextItem = $nextItem; - $this->total = $total; } - /** - * @return int|null - */ public function getNextItem(): ?int { return $this->nextItem; } - /** - * @return int|null - */ public function getTotal(): ?int { return $this->total; diff --git a/src/Core/Response/DTO/RenewedAccessToken.php b/src/Core/Response/DTO/RenewedAccessToken.php index 3ed060da..9b1cbde3 100644 --- a/src/Core/Response/DTO/RenewedAccessToken.php +++ b/src/Core/Response/DTO/RenewedAccessToken.php @@ -7,99 +7,51 @@ use Bitrix24\SDK\Core\Credentials\AccessToken; use Bitrix24\SDK\Core\Credentials\Scope; -/** - * Class RenewedAccessToken - * - * @package Bitrix24\SDK\Core\Response\DTO - */ -class RenewedAccessToken +readonly class RenewedAccessToken { - private AccessToken $accessToken; - private string $memberId; - private string $clientEndpoint; - private string $serverEndpoint; - private string $applicationStatus; - private string $domain; - /** * RenewedAccessToken constructor. - * - * @param AccessToken $accessToken - * @param string $memberId - * @param string $clientEndpoint - * @param string $serverEndpoint - * @param string $applicationStatus - * @param string $domain */ public function __construct( - AccessToken $accessToken, - string $memberId, - string $clientEndpoint, - string $serverEndpoint, - string $applicationStatus, - string $domain - ) { - $this->accessToken = $accessToken; - $this->memberId = $memberId; - $this->clientEndpoint = $clientEndpoint; - $this->serverEndpoint = $serverEndpoint; - $this->applicationStatus = $applicationStatus; - $this->domain = $domain; + private AccessToken $accessToken, + private string $memberId, + private string $clientEndpoint, + private string $serverEndpoint, + private string $applicationStatus, + private string $domain) + { } - /** - * @return AccessToken - */ public function getAccessToken(): AccessToken { return $this->accessToken; } - /** - * @return string - */ public function getMemberId(): string { return $this->memberId; } - /** - * @return string - */ public function getClientEndpoint(): string { return $this->clientEndpoint; } - /** - * @return string - */ public function getServerEndpoint(): string { return $this->serverEndpoint; } - /** - * @return string - */ public function getApplicationStatus(): string { return $this->applicationStatus; } - /** - * @return string - */ public function getDomain(): string { return $this->domain; } - /** - * @param array $response - * - * @return self - */ public static function initFromArray(array $response): self { return new self( diff --git a/src/Core/Response/DTO/ResponseData.php b/src/Core/Response/DTO/ResponseData.php index f50484ff..481defa0 100644 --- a/src/Core/Response/DTO/ResponseData.php +++ b/src/Core/Response/DTO/ResponseData.php @@ -4,50 +4,28 @@ namespace Bitrix24\SDK\Core\Response\DTO; -/** - * Class ResponseData - * - * @package Bitrix24\SDK\Core\Response\DTO - */ class ResponseData { - protected array $result; - protected Time $time; - protected Pagination $pagination; - /** * ResponseData constructor. - * - * @param array $result - * @param Time $time - * @param Pagination $pagination */ - public function __construct(array $result, Time $time, Pagination $pagination) + public function __construct( + protected array $result, + readonly protected Time $time, + readonly protected Pagination $pagination) { - $this->result = $result; - $this->time = $time; - $this->pagination = $pagination; } - /** - * @return Pagination - */ public function getPagination(): Pagination { return $this->pagination; } - /** - * @return Time - */ public function getTime(): Time { return $this->time; } - /** - * @return array - */ public function getResult(): array { return $this->result; diff --git a/src/Core/Response/DTO/Time.php b/src/Core/Response/DTO/Time.php index 3e83f84b..cfaaca27 100644 --- a/src/Core/Response/DTO/Time.php +++ b/src/Core/Response/DTO/Time.php @@ -5,133 +5,71 @@ namespace Bitrix24\SDK\Core\Response\DTO; use DateTimeImmutable; +use Exception; -/** - * Class Time - * - * @package Bitrix24\SDK\Core\Response\DTO - */ -class Time +readonly class Time { - private float $start; - private float $finish; - private float $duration; - private float $processing; - /** - * @var float $operating sum of query execution time - * @see https://training.bitrix24.com/rest_help/rest_sum/operating.php - */ - private float $operating; // time in seconds - private DateTimeImmutable $dateStart; - private DateTimeImmutable $dateFinish; - /** - * @var int|null time to reset nearest limit part - * @see https://training.bitrix24.com/rest_help/rest_sum/operating.php - */ - private ?int $operatingResetAt; - - /** - * Time constructor. - * - * @param float $start - * @param float $finish - * @param float $duration - * @param float $processing - * @param float $operating - * @param \DateTimeImmutable $dateStart - * @param \DateTimeImmutable $dateFinish - * @param int|null $operatingResetAt - */ public function __construct( - float $start, - float $finish, - float $duration, - float $processing, - float $operating, - DateTimeImmutable $dateStart, - DateTimeImmutable $dateFinish, - ?int $operatingResetAt + private float $start, + private float $finish, + private float $duration, + private float $processing, + /** + * @see https://training.bitrix24.com/rest_help/rest_sum/operating.php + */ + private float $operating, + private DateTimeImmutable $dateStart, + private DateTimeImmutable $dateFinish, + /** + * @see https://training.bitrix24.com/rest_help/rest_sum/operating.php + */ + private ?int $operatingResetAt ) { - $this->start = $start; - $this->finish = $finish; - $this->duration = $duration; - $this->processing = $processing; - $this->operating = $operating; - $this->dateStart = $dateStart; - $this->dateFinish = $dateFinish; - $this->operatingResetAt = $operatingResetAt; } - /** - * @return float - */ public function getStart(): float { return $this->start; } - /** - * @return float - */ public function getFinish(): float { return $this->finish; } - /** - * @return float - */ public function getDuration(): float { return $this->duration; } - /** - * @return float - */ public function getProcessing(): float { return $this->processing; } - /** - * @return float - */ public function getOperating(): float { return $this->operating; } - /** - * @return int|null - */ public function getOperatingResetAt(): ?int { return $this->operatingResetAt; } - /** - * @return \DateTimeImmutable - */ public function getDateStart(): DateTimeImmutable { return $this->dateStart; } - /** - * @return \DateTimeImmutable - */ public function getDateFinish(): DateTimeImmutable { return $this->dateFinish; } /** - * @param array $response - * - * @return self - * @throws \Exception + * @throws Exception */ public static function initFromResponse(array $response): self { diff --git a/src/Core/Response/Response.php b/src/Core/Response/Response.php index 7129653c..13cb3ac1 100644 --- a/src/Core/Response/Response.php +++ b/src/Core/Response/Response.php @@ -14,63 +14,39 @@ use Symfony\Contracts\HttpClient\ResponseInterface; use Throwable; -/** - * Class Response - * - * @package Bitrix24\SDK\Core\Response - */ class Response { - protected ResponseInterface $httpResponse; - protected ?DTO\ResponseData $responseData; - protected Command $apiCommand; - protected ApiLevelErrorHandler $apiLevelErrorHandler; - protected LoggerInterface $logger; + protected ?DTO\ResponseData $responseData = null; /** * Response constructor. - * - * @param ResponseInterface $httpResponse - * @param Command $apiCommand - * @param ApiLevelErrorHandler $apiLevelErrorHandler - * @param LoggerInterface $logger */ - public function __construct(ResponseInterface $httpResponse, Command $apiCommand, - ApiLevelErrorHandler $apiLevelErrorHandler, - LoggerInterface $logger) + public function __construct( + protected ResponseInterface $httpResponse, + protected Command $apiCommand, + protected ApiLevelErrorHandler $apiLevelErrorHandler, + protected LoggerInterface $logger) { - $this->httpResponse = $httpResponse; - $this->apiCommand = $apiCommand; - $this->apiLevelErrorHandler = $apiLevelErrorHandler; - $this->logger = $logger; - $this->responseData = null; } - /** - * @return ResponseInterface - */ public function getHttpResponse(): ResponseInterface { return $this->httpResponse; } - /** - * @return Command - */ public function getApiCommand(): Command { return $this->apiCommand; } /** - * @return DTO\ResponseData * @throws BaseException */ public function getResponseData(): DTO\ResponseData { $this->logger->debug('getResponseData.start'); - if ($this->responseData === null) { + if (!$this->responseData instanceof \Bitrix24\SDK\Core\Response\DTO\ResponseData) { try { $this->logger->debug('getResponseData.parseResponse.start'); $responseResult = $this->httpResponse->toArray(true); @@ -90,6 +66,7 @@ public function getResponseData(): DTO\ResponseData if (array_key_exists('next', $responseResult)) { $nextItem = (int)$responseResult['next']; } + if (array_key_exists('total', $responseResult)) { $total = (int)$responseResult['total']; } @@ -110,21 +87,19 @@ public function getResponseData(): DTO\ResponseData throw new BaseException(sprintf('api request error: %s', $exception->getMessage()), $exception->getCode(), $exception); } } + $this->logger->debug('getResponseData.finish'); return $this->responseData; } - /** - * @return string|null - */ private function getHttpResponseContent(): ?string { $content = null; try { $content = $this->httpResponse->getContent(false); - } catch (Throwable $exception) { - $this->logger->error($exception->getMessage()); + } catch (Throwable $throwable) { + $this->logger->error($throwable->getMessage()); } return $content; From 81be56414f6744a1dbf2388fdefa65a50348a8fd Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 1 Jul 2024 01:12:30 +0600 Subject: [PATCH 070/138] Update 'order' array population in Batch.php The 'order' parameter in Batch.php was updated to be populated with the $order variable, previously it was initiated as an empty array. This change accommodates more specific sorting requirements in batch operations. Signed-off-by: mesilov --- src/Core/Batch.php | 2 +- .../Core/BatchGetTraversableTest.php | 43 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/Core/Batch.php b/src/Core/Batch.php index fee688bc..306a5a2e 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -494,7 +494,7 @@ public function getTraversableList( } $params = [ - 'order' => [], + 'order' => $order, 'filter' => $this->updateFilterForBatch($keyId, $startId, $lastElementIdInPage, $isLastPage, $filter), 'select' => $select, 'start' => -1, diff --git a/tests/Integration/Core/BatchGetTraversableTest.php b/tests/Integration/Core/BatchGetTraversableTest.php index 92e0c4e4..f21bdbf9 100644 --- a/tests/Integration/Core/BatchGetTraversableTest.php +++ b/tests/Integration/Core/BatchGetTraversableTest.php @@ -106,6 +106,49 @@ public function testSingleBatchWithMoreThanOnePageAndLimit(): void $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 From 5811210978a85d8e15d3ffb6f1f56b64810284c6 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 1 Jul 2024 01:25:50 +0600 Subject: [PATCH 071/138] Add integration tests for Core and update exceptions Integration tests have been added for the Core component. The Makefile and phpunit.xml.dist files were updated to reflect these new tests. Further, exceptions in CoreTest.php and Core.php have been adjusted to better handle Transport and Json exceptions. Signed-off-by: mesilov --- Makefile | 4 +++- phpunit.xml.dist | 3 +++ src/Core/Core.php | 8 +++++--- tests/Integration/Core/CoreTest.php | 5 +++-- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 5c55b787..cd389856 100644 --- a/Makefile +++ b/Makefile @@ -18,4 +18,6 @@ test-integration-scope-telephony: test-integration-scope-workflows: vendor/bin/phpunit --testsuite integration_tests_scope_workflows test-integration-scope-user: - vendor/bin/phpunit --testsuite integration_tests_scope_user \ No newline at end of file + vendor/bin/phpunit --testsuite integration_tests_scope_user +test-integration-core: + vendor/bin/phpunit --testsuite integration_tests_core \ No newline at end of file diff --git a/phpunit.xml.dist b/phpunit.xml.dist index d16b93db..e878d19c 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -10,6 +10,9 @@ ./tests/Integration + + ./tests/Integration/Core/ + ./tests/Integration/Services/Telephony/ diff --git a/src/Core/Core.php b/src/Core/Core.php index 3b533680..bbbe7ef6 100644 --- a/src/Core/Core.php +++ b/src/Core/Core.php @@ -16,6 +16,7 @@ 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; @@ -29,7 +30,7 @@ class Core implements CoreInterface /** * Main constructor. */ - public function __construct(protected ApiClientInterface $apiClient, protected ApiLevelErrorHandler $apiLevelErrorHandler, protected EventDispatcherInterface $eventDispatcher, protected LoggerInterface $logger) + public function __construct(protected ApiClientInterface $apiClient, protected ApiLevelErrorHandler $apiLevelErrorHandler, protected EventDispatcherInterface $eventDispatcher, protected LoggerInterface $logger) { } @@ -176,7 +177,7 @@ public function call(string $apiMethod, array $parameters = []): Response $this->apiLevelErrorHandler->handle($body); break; } - } catch (TransportExceptionInterface $exception) { + } catch (TransportExceptionInterface|JsonException $exception) { // catch symfony http client transport exception $this->logger->error( 'call.transportException', @@ -185,7 +186,7 @@ public function call(string $apiMethod, array $parameters = []): Response 'message' => $exception->getMessage(), ] ); - throw new TransportException(sprintf('transport error - %s', $exception->getMessage()), $exception->getCode(), $exception); + 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; @@ -194,6 +195,7 @@ public function call(string $apiMethod, array $parameters = []): Response 'call.unknownException', [ 'message' => $exception->getMessage(), + 'class' => $exception::class, 'trace' => $exception->getTrace(), ] ); diff --git a/tests/Integration/Core/CoreTest.php b/tests/Integration/Core/CoreTest.php index f6b6c004..becfb839 100644 --- a/tests/Integration/Core/CoreTest.php +++ b/tests/Integration/Core/CoreTest.php @@ -10,8 +10,8 @@ use Bitrix24\SDK\Core\Credentials\ApplicationProfile; use Bitrix24\SDK\Core\Credentials\Credentials; use Bitrix24\SDK\Core\Credentials\Scope; -use Bitrix24\SDK\Core\Exceptions\AuthForbiddenException; 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; @@ -37,13 +37,14 @@ public function testCallExistingApiMethod(): void public function testConnectToNonExistsBitrix24PortalInCloud():void { $core = (new CoreBuilder()) + ->withLogger($this->log) ->withCredentials(Credentials::createFromOAuth( new AccessToken('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(AuthForbiddenException::class); + $this->expectException(TransportException::class); $core->call('app.info'); } From 22871a0f699cfd762905d48944532c8f4d00011c Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 1 Jul 2024 01:37:05 +0600 Subject: [PATCH 072/138] Refactor Credentials constructor and simplify code The Credentials constructor has been simplified by removing redundant comments and checks. Error checking has been improved - it now ensures that either an AccessToken or WebhookUrl must be set for authentication. The code readability has also been enhanced by removing the full namespace from instance checks, using the imported class names instead. A minor change was also made in the Batch.php file to enhance code formatting. Signed-off-by: mesilov --- src/Core/Batch.php | 1 + src/Core/Credentials/Credentials.php | 21 +++++++-------------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/Core/Batch.php b/src/Core/Batch.php index 306a5a2e..dbbd17d5 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -387,6 +387,7 @@ public function getTraversableList( $params = array_merge($params, $additionalParameters); } + $keyId = $isCrmItemsInBatch ? 'id' : 'ID'; $firstResultPage = $this->core->call($apiMethod, $params); diff --git a/src/Core/Credentials/Credentials.php b/src/Core/Credentials/Credentials.php index a174a010..9adae014 100644 --- a/src/Core/Credentials/Credentials.php +++ b/src/Core/Credentials/Credentials.php @@ -12,33 +12,26 @@ class Credentials protected ?string $domainUrl = null; /** - * Credentials constructor. - * - * * @throws InvalidArgumentException */ public function __construct( protected ?WebhookUrl $webhookUrl, protected ?AccessToken $accessToken, protected ?ApplicationProfile $applicationProfile, - ?string $domainUrl + ?string $domainUrl ) { if ($domainUrl !== null) { $this->setDomainUrl($domainUrl); } - if (!$this->accessToken instanceof \Bitrix24\SDK\Core\Credentials\AccessToken && !$this->webhookUrl instanceof \Bitrix24\SDK\Core\Credentials\WebhookUrl) { - throw new \LogicException('you must set on of auth type: webhook or OAuth 2.0'); + if (!$this->accessToken instanceof AccessToken && !$this->webhookUrl instanceof WebhookUrl) { + throw new InvalidArgumentException('you must set on of auth type: webhook or OAuth 2.0'); } - if (!$this->accessToken instanceof \Bitrix24\SDK\Core\Credentials\AccessToken) { - return; - } - if ($this->domainUrl !== null) { - return; + if ($this->accessToken instanceof AccessToken && $this->domainUrl === null) { + throw new InvalidArgumentException('for oauth type you must set domain url'); } - throw new \LogicException('for oauth type you must set domain url'); } public function setAccessToken(AccessToken $accessToken): void @@ -68,7 +61,7 @@ public function setDomainUrl(string $domainUrl): void public function isWebhookContext(): bool { - return $this->webhookUrl instanceof \Bitrix24\SDK\Core\Credentials\WebhookUrl && !$this->accessToken instanceof \Bitrix24\SDK\Core\Credentials\AccessToken; + return $this->webhookUrl instanceof WebhookUrl && !$this->accessToken instanceof AccessToken; } public function getApplicationProfile(): ?ApplicationProfile @@ -78,7 +71,7 @@ public function getApplicationProfile(): ?ApplicationProfile public function getDomainUrl(): string { - $arUrl = $this->getWebhookUrl() instanceof \Bitrix24\SDK\Core\Credentials\WebhookUrl ? parse_url($this->getWebhookUrl()->getUrl()) : parse_url((string) $this->domainUrl); + $arUrl = $this->getWebhookUrl() instanceof WebhookUrl ? parse_url($this->getWebhookUrl()->getUrl()) : parse_url((string)$this->domainUrl); return sprintf('%s://%s', $arUrl['scheme'], $arUrl['host']); } From ef7d3031d6b8b7ad439dfc0a8b3ae054a92dab03 Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 3 Jul 2024 00:20:16 +0600 Subject: [PATCH 073/138] Replace `ramsey/uuid` with `symfony/uid` package The existing dependency on `ramsey/uuid` has been replaced with `symfony/uid` in the codebase. This change is reflected in the `Command` constructor of `src/Core/Commands/Command.php`, and anywhere else where the ID of a command was previously retrieved using `getUuid()`. The `getName()` method has also been replaced with `getId()`. The composer.json and CHANGELOG files have been updated correspondingly. Signed-off-by: mesilov --- CHANGELOG.md | 5 ++++- composer.json | 1 - src/Core/Batch.php | 4 ++-- src/Core/Commands/Command.php | 37 ++++++++++------------------------- 4 files changed, 16 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bca988bd..85507298 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,6 +60,7 @@ * improve DX - add [Rector](https://github.com/rectorphp/rector) for improve code quality and speed up releases cycle ### Changed +* ❗️ migrate from `ramsey/uuid` to `symfony/uid` * ❗️ update scope `telephony`, scope fully rewritten * `ExternalCall` – work with external call: * `getCallRecordUploadUrl` – get url for upload call record file @@ -115,7 +116,9 @@ * add `CrmEntityType` – crm entity type enum * add `PbxType` – pbx type enum * add `SipRegistrationStatus` – pbx sip line registration status -* change signature `Bitrix24\SDK\Core\Credentials\AccessToken::getRefreshToken()?string;` - add nullable option for event tokens +* 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` + ### Deleted * remove class `Bitrix24\SDK\Application\Requests\Events\OnApplicationInstall\Auth` diff --git a/composer.json b/composer.json index bd2af157..94d969dd 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,6 @@ "ext-intl": "*", "psr/log": "^2 || ^3", "fig/http-message-util": "1.1.*", - "ramsey/uuid": "^3 ||^4", "nesbot/carbon": "3.3.*", "moneyphp/money": "^3 || ^4", "symfony/http-client": "^6 || ^7", diff --git a/src/Core/Batch.php b/src/Core/Batch.php index dbbd17d5..38d1f540 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -737,7 +737,7 @@ protected function getTraversable(bool $isHaltOnError): Generator [ 'batchItemNumber' => $batchItem, 'batchApiCommand' => $traversableBatchResult->getApiCommand()->getApiMethod(), - 'batchApiCommandUuid' => $traversableBatchResult->getApiCommand()->getUuid()->toString(), + 'batchApiCommandId' => $traversableBatchResult->getApiCommand()->getId(), ] ); // todo try to multiplex requests @@ -831,7 +831,7 @@ private function convertToApiCommands(): array { $apiCommands = []; foreach ($this->commands as $command) { - $apiCommands[$command->getName() ?? $command->getUuid()->toString()] = sprintf( + $apiCommands[$command->getId()] = sprintf( '%s?%s', $command->getApiMethod(), http_build_query($command->getParameters()) diff --git a/src/Core/Commands/Command.php b/src/Core/Commands/Command.php index a4a6e37e..1a36caba 100644 --- a/src/Core/Commands/Command.php +++ b/src/Core/Commands/Command.php @@ -4,35 +4,18 @@ namespace Bitrix24\SDK\Core\Commands; -use Ramsey\Uuid\Uuid; -use Ramsey\Uuid\UuidInterface; +use Symfony\Component\Uid\Uuid; -/** - * Class Command - * - * @package Bitrix24\SDK\Core\Commands - */ class Command { - private readonly string $name; - - private readonly \Ramsey\Uuid\UuidInterface $uuid; - - /** - * BatchCommand constructor. - * - * - * @throws \Exception - */ - public function __construct(private readonly string $apiMethod, private readonly array $parameters, ?string $name = null) - { - $this->uuid = Uuid::uuid4(); - $this->name = $name ?? $this->uuid->toString(); - } - - public function getUuid(): UuidInterface + public function __construct( + private readonly string $apiMethod, + private readonly array $parameters, + private ?string $id = null) { - return $this->uuid; + if ($id === null) { + $this->id = (Uuid::v7())->toRfc4122(); + } } public function getApiMethod(): string @@ -45,8 +28,8 @@ public function getParameters(): array return $this->parameters; } - public function getName(): ?string + public function getId(): string { - return $this->name; + return $this->id; } } From 074556e06f7749d21a65ee561ad17c96742d969f Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 3 Jul 2024 00:39:22 +0600 Subject: [PATCH 074/138] Remove Bitrix24Account contracts Deleted the Bitrix24Account contracts: Bitrix24AccountInterface, Bitrix24AccountRepositoryInterface, and Bitrix24AccountStatus. This is part of a broader refactor of the Bitrix24\SDK\Application\Contracts as noted in the changelog. Signed-off-by: mesilov --- CHANGELOG.md | 2 + .../Bitrix24AccountInterface.php | 114 ------------------ .../Bitrix24AccountRepositoryInterface.php | 55 --------- .../Bitrix24Account/Bitrix24AccountStatus.php | 16 --- 4 files changed, 2 insertions(+), 185 deletions(-) delete mode 100644 src/Application/Contracts/Bitrix24Account/Bitrix24AccountInterface.php delete mode 100644 src/Application/Contracts/Bitrix24Account/Bitrix24AccountRepositoryInterface.php delete mode 100644 src/Application/Contracts/Bitrix24Account/Bitrix24AccountStatus.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 85507298..8dc0e01e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,6 +61,8 @@ ### Changed * ❗️ migrate from `ramsey/uuid` to `symfony/uid` +* ❗️ refactor `Bitrix24\SDK\Application\Contracts`: + * ❗️ update scope `telephony`, scope fully rewritten * `ExternalCall` – work with external call: * `getCallRecordUploadUrl` – get url for upload call record file diff --git a/src/Application/Contracts/Bitrix24Account/Bitrix24AccountInterface.php b/src/Application/Contracts/Bitrix24Account/Bitrix24AccountInterface.php deleted file mode 100644 index 654f377b..00000000 --- a/src/Application/Contracts/Bitrix24Account/Bitrix24AccountInterface.php +++ /dev/null @@ -1,114 +0,0 @@ - - */ - public function findAllActive(): array; - - /** - * @return array - */ - public function findAllDeactivated(): array; -} \ No newline at end of file diff --git a/src/Application/Contracts/Bitrix24Account/Bitrix24AccountStatus.php b/src/Application/Contracts/Bitrix24Account/Bitrix24AccountStatus.php deleted file mode 100644 index bcb29b22..00000000 --- a/src/Application/Contracts/Bitrix24Account/Bitrix24AccountStatus.php +++ /dev/null @@ -1,16 +0,0 @@ - Date: Thu, 4 Jul 2024 02:48:19 +0600 Subject: [PATCH 075/138] Add Bitrix24AccountInterface and Bitrix24AccountStatus Added two new PHP classes under the directory src/Application/Contracts/Bitrix24Accounts/Entity. `Bitrix24AccountInterface` provides an interface for handling Bitrix24 account related operations. `Bitrix24AccountStatus` is an enumeration that defines possible statuses for a Bitrix24 account. Signed-off-by: mesilov --- .../Entity/Bitrix24AccountInterface.php | 124 ++++++++++++++++++ .../Entity/Bitrix24AccountStatus.php | 13 ++ 2 files changed, 137 insertions(+) create mode 100644 src/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterface.php create mode 100644 src/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountStatus.php diff --git a/src/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterface.php b/src/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterface.php new file mode 100644 index 00000000..5eee782f --- /dev/null +++ b/src/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterface.php @@ -0,0 +1,124 @@ + Date: Fri, 5 Jul 2024 01:47:40 +0600 Subject: [PATCH 076/138] Remove numerous obsolete documentation files The commit involves the deletion of several redundant files related to the documentation of the project. The files were scattered across different sections like Core, Results, Events, and Application. They consisted of guidelines for adding new functionality, usage of different features, and instructions for tasks like Authorization on the portal. These files were not serving any purpose and cluttering the repository, hence removed. Signed-off-by: mesilov --- docs/RU/Application/new-local-application.md | 23 ---- docs/RU/Core/Auth/auth.md | 82 ------------- docs/RU/Core/Batch/batch-read-mode.md | 121 ------------------- docs/RU/Core/Events/events.md | 8 -- docs/RU/Core/Response/response.md | 10 -- docs/RU/Core/Result/result.md | 92 -------------- docs/RU/documentation.md | 103 ---------------- docs/RU/how-to-add-new-scope/new-scope.md | 110 ----------------- 8 files changed, 549 deletions(-) delete mode 100644 docs/RU/Application/new-local-application.md delete mode 100644 docs/RU/Core/Auth/auth.md delete mode 100644 docs/RU/Core/Batch/batch-read-mode.md delete mode 100644 docs/RU/Core/Events/events.md delete mode 100644 docs/RU/Core/Response/response.md delete mode 100644 docs/RU/Core/Result/result.md delete mode 100644 docs/RU/documentation.md delete mode 100644 docs/RU/how-to-add-new-scope/new-scope.md diff --git a/docs/RU/Application/new-local-application.md b/docs/RU/Application/new-local-application.md deleted file mode 100644 index 393a65a3..00000000 --- a/docs/RU/Application/new-local-application.md +++ /dev/null @@ -1,23 +0,0 @@ -# Создание Локального приложения -## Предусловия -1. Создайте 2 файла в корне рабочей папки например app: это `install.php` и `index.php`. -2. Содержимое файла `install.php`. - ```php - ``` -3. Для работы локального серверного приложения требуется рабочий веб сервер на машине разработчика. -4. Запускаем локальный веб-сервер, например так: -```shell -php -S 127.0.0.1:8080 -``` -3. Пробрасываем порт в большой интернет через сервис ngrok. -```shell -ngrok http 127.0.0.1:8080 -``` -4. После запуска ngrok будет выдан временный публичный адрес типо `https://7949-178-34-183-66.eu.ngrok.io`, который после выключения сервиса перестанет существовать. Этот адрес исчезнет после завершения ngrok. -5. Зарегистрируйте новый портал битрикс 24. -6. Включите тестовый период для маркет плейса и тарифного плана. -7. Открой портал и перейдите в меню. - 1. Откройте левое меню, выберите "Разработчикам" - 2. Выберите "Другое" - 3. Откройте "Локальное приложение" - 4. Зарегистрируйте новое локальное приложение с нужным вам скоупом. diff --git a/docs/RU/Core/Auth/auth.md b/docs/RU/Core/Auth/auth.md deleted file mode 100644 index eaf66877..00000000 --- a/docs/RU/Core/Auth/auth.md +++ /dev/null @@ -1,82 +0,0 @@ -# Авторизация с использованием «Входящего вебхука» - -## Документация -[Веб-хуки. Быстрый старт](https://dev.1c-bitrix.ru/learning/course/?COURSE_ID=99&LESSON_ID=8581) - -## подключение к Битрикс24 с использованием входящих веб-хуков -1. Создайте вебхук -2. Установите библиотеку -3. Сконфигурируйте ApiClient для использования авторизации через входящий веб-хук - -```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, - null -); - -$apiClient = new \Bitrix24\SDK\Core\ApiClient($credentials, $client, $log); - -$result = $apiClient->getResponse('app.info'); -$result = json_decode($result->getContent(), true); -var_dump($result); -``` - -## подключение к Битрикс24 с использованием OAuth 2.0 - -```php -pushHandler(new StreamHandler('b24-api-client-debug.log', Logger::DEBUG)); - -$client = HttpClient::create(['http_version' => '2.0']); -$traceableClient = new \Symfony\Component\HttpClient\TraceableHttpClient($client); -$traceableClient->setLogger($log); - -$appProfile = new \Bitrix24\SDK\Core\Credentials\ApplicationProfile( - 'client id from application settings', - 'client secret from application settings', - new \Bitrix24\SDK\Core\Credentials\Scope( - [ - 'crm', - ] - ) -); -$token = new \Bitrix24\SDK\Core\Credentials\AccessToken( - '50cc9d5… access token', - '404bc55… refresh token', - 1604179882 -); -$domain = 'https:// client portal address .bitrix24.ru'; -$credentials = \Bitrix24\SDK\Core\Credentials\Credentials::createFromOAuth($token, $appProfile, $domain); - -$apiClient = new \Bitrix24\SDK\Core\ApiClient($credentials, $traceableClient, $log); -$app = new \Bitrix24\SDK\Services\Main($apiClient, $log); - -$log->debug('================================'); -$res = $app->call('app.info'); -var_dump($res->getResponseData()->getResult()->getResultData()); -``` \ No newline at end of file diff --git a/docs/RU/Core/Batch/batch-read-mode.md b/docs/RU/Core/Batch/batch-read-mode.md deleted file mode 100644 index 11d4634c..00000000 --- a/docs/RU/Core/Batch/batch-read-mode.md +++ /dev/null @@ -1,121 +0,0 @@ -# Batch-режим чтения данных из Битрикс24 - -## Описание задачи - -В CRM у сущности более 100 000 элементов, требуется получить эти данные в клиентском коде. У сущности добавлены пользовательские поля, -порядка десяти штук, разного типа. - -В зависимости от ситуации перед разработчиком может стоять задача: - -- получить полный набор полей сущности, например, для выгрузки в аналитическую систему; -- получить отдельные поля сущности; -- по умолчанию, при выборке производится подсчёт количества элементов в выборке, на больших объёмах это дорогостоящая операция, если - передать флаг count=-1, то подсчёт элементов можно отключить - -## Документация и примечания - -https://dev.1c-bitrix.ru/rest_help/general/batch.php - -- По умолчанию, за 1 запрос `crm.contacts.lists` возвращается 50 элементов. -- батч-запрос может выполнить до 50 запросов, т.е. за один батч-запрос можно получить 2500 элементов - -## Тестирование быстродействия - -Предусловия: - -- облачный Битрикс24 -- количество сущностей одного типа в CRM — 100 000 штук. -- BITRIX24-PHP-SDK запускается на машине разработчика -- работаем с сущностью `crm.contacts` - -### Параметры получения данных - -**order** - -- `default`: сущность по которой будет производится сортировка и направление сортировки не передаются -- `custom`: `DATE_CREATE=>ASC` - -**filter** - -- полная выборка `'>ID' => 1`; -- данные за период (фильтр по дате создания) - -**select** - -- частичная (`partial`) выборка полей сущности: `ID`, `NAME`, `LAST_NAME`, `DATE_CREATE`, `PHONE`, `EMAIL` -- системные поля (`system`) cущности: `*`, `PHONE`, `EMAIL`, `IM` -- все поля (`all`) сущности: `*`, `PHONE`, `EMAIL`, `IM`, `UF_*` - -### Запуск тестового кода - -Код замера лежит в папке `tools\PerformanceBenchmarks\`, запускается как CLI-команда. - -```shell -mesilov@mesilov-local bitrix24-php-sdk % php -d memory_limit=500M -f tools/bin/console benchmark:list -help -Description: - performance benchmark for *.list method - -Usage: - benchmark:list [options] - -Options: - --webhook=WEBHOOK bitrix24 incoming webhook [default: ""] - --rounds=ROUNDS benchmark rounds count [default: 3] - --fields=FIELDS select fields mode (partial | system | all) [default: "all"] - --count=COUNT read elements count [default: 50] - -h, --help Display help for the given command. When no command is given display help for the list command - -q, --quiet Do not output any message - -V, --version Display this application version - --ansi Force ANSI output - --no-ansi Disable ANSI output - -n, --no-interaction Do not ask any interactive question - -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug - -Help: - performance benchmark for *.list method with simple or batch mode if need read more than 50 elements -``` - -### Варианты выборки - -1. сортировка, подсчёт количества элементов в выборке -2. сортировка, без подсчёта количества элементов в выборке -3. сортировка по умолчанию, подсчёт количества элементов в выборке -4. сортировка по умолчанию, без подсчёта количества элементов в выборке - -### Чтение 50 элементов — отдельные поля \ вся сущность \ вся сущность + пользовательские поля - -Стандартная выборка 50 элементов приведена для сравнения с батч-режимом. Время — секунды, округление до 4 знаков. - -Режим | отдельные поля | вся сущность | вся сущность + UF_* ---- | --- | --- | --- -сортировка, подсчёт количества элементов в выборке | 0.3786 | 2.6767 | 3.1891 -сортировка, без подсчёта количества элементов в выборке | 0.3125 | 1.745 | 1.956 -сортировка по умолчанию, подсчёт количества элементов в выборке | 0.3129 | 1.3176 | 1.523 -сортировка по умолчанию, без подсчёта количества элементов в выборке | **0.2241** | **0.458** | **0.4858** - -### Чтение 2700 элементов в batch-режиме отдельные поля \ вся сущность \ вся сущность + пользовательские поля - -Сами запросы строятся сервисом `Bitrix24\SDK\Core\Batch` Время — секунды, округление до 4 знаков. - -Режим | отдельные поля | вся сущность | вся сущность + UF_* ---- | --- | --- | --- -сортировка, подсчёт количества элементов в выборке | 19.7924 | 131.3065 | 168.753 -сортировка, без подсчёта количества элементов в выборке | 27.0083 | **30.8689** | **32.6827** -сортировка по умолчанию, подсчёт количества элементов в выборке | **14.3636** | 70.5149 | 79.5987 -сортировка по умолчанию, без подсчёта количества элементов в выборке | 26.5045 | 31.1381 | 33.8329 - -## Подготовка тестового окружения - -Сгенерируйте тестовые контакты для вашего dev-окружения используя CLI-команду из папки tools -`generate:contacts` - -## Комментарии - -1. В текущей версии статьи в портале было 100к элементов в сущности, эта ситуация характерна для небольшого количества порталов -2. Замеры производились когда на портале отсутствовала операционная нагрузка характерная для рабочего дня -3. По возможности старайтесь избегать выборки всех данных -4. Сортировка данных при больших выборках тоже дорогая операция -5. Имеет смысл сделать замеры при изменении количества элементов на портале 10к до 500к элементов с шагом 20к элементов. -6. В коробочной версии Битрикс24 показатели могут существенно отличаться -7. В SDK выделен отдельный сервис `Core\BulkItemsReader` который реализует более эффективные стратегии чем простой batch, на текущий момент - оптимизация скорости чтения данных не производилась, используется стратегия «батч без подсчёта количества элементов» diff --git a/docs/RU/Core/Events/events.md b/docs/RU/Core/Events/events.md deleted file mode 100644 index d4dbc56c..00000000 --- a/docs/RU/Core/Events/events.md +++ /dev/null @@ -1,8 +0,0 @@ -# Events -SDK может уведомить клиентский код о наступлении событий связанных с жизненным циклом приложения. - -## Событие «AUTH_TOKEN_RENEWED» — обновлён токен авторизации -Выбрасывается после того, как библиотека сама обновила авторизационный токен и выполнила с ним первый удачный запрос. -Подписавшись на это событие у вас будет возможность сохранить новую пару: -- accessToken -- refreshToken \ No newline at end of file diff --git a/docs/RU/Core/Response/response.md b/docs/RU/Core/Response/response.md deleted file mode 100644 index f9902d12..00000000 --- a/docs/RU/Core/Response/response.md +++ /dev/null @@ -1,10 +0,0 @@ -# Возвращаемый результат - -ApiClient возвращает результат в виде объекта `Symfony\Contracts\HttpClient\ResponseInterface` - -В клиентский код возвращается объект типа `Core\Response\DTO` который имеет метод `getResponseData(): DTO\ResponseData` -он конструирует унифицированный DTO ответа сервера состоящий из двух полей -- результат работы в виде массива -- время работы – объект типа `Core\Response\DTO\Time` - -Т.е. для удобства работы всегда имеет смысл работать с объектом `Core\Response\DTO` \ No newline at end of file diff --git a/docs/RU/Core/Result/result.md b/docs/RU/Core/Result/result.md deleted file mode 100644 index 129ff907..00000000 --- a/docs/RU/Core/Result/result.md +++ /dev/null @@ -1,92 +0,0 @@ -# Типизированные результаты вызова API-методов - -Результатом работы API-методов является унифицированный объект `SDK\Core\Response\Response`, но с ним неудобно работать, т.к. он -предоставляет только «общие» методы. В зависимости от типа API-метода сервисы SDK возвращают типизированные результаты. - -## Общие принципы - -1. Сервисы возвращают типизированные результаты -2. Результаты работы сервиса находятся в одноимённом пространстве имён `Result` который принадлежит сервису сущности. -3. Часть унифицированных результатов вынесена в пространство имён `Core\Result` и используется всеми сервисами, унифицированные результаты - перечислены ниже: - -## Результат добавления сущности — AddItemResult - -Является результатом добавления сущности при вызове метода *.add - -Содержит метод `getId():int` который позволяет получить идентификатор добавленной сущности. - -## Результат удаления сущности — DeletedItemResult - -Является результатом удаления сущности при вызове метода *.delete - -Содержит метод `isSuccess(): bool` который позволяет понять, была ли успешна операция удаления сущности. - -## Результат изменения сущности — UpdatedItemResult - -Является результатом изменения сущности при вызове метода *.update - -Содержит метод `isSuccess(): bool` который позволяет понять, была ли успешна операция изменения сущности. - -## Результат получения описания списка полей — FieldsResult - -Является результатом вызова метода с описанием метаданных полей *.fields - -Содержит метод `getFieldsDescription(): array` который позволяет получить описание полей для конкретной сущности - -## Результат получения сущности — *ItemResult - -Является результатом получения сущности или её части, наследуется от `Core\Result\AbstractItem` - -Принципы по которым формируются объекты: - -1. Результат чтения данных из API - неизменяемый -2. В результате чтения может быть получена как вся сущность, так и её часть. -3. Для системных полей сущности SDK предоставляет автокомплит свойств с помощью phpdoc параметров - -Пример описания свойств сделки для объекта `\Bitrix24\SDK\Services\CRM\Deal\Result\DealItemResult` - -```php -/** - * Class DealItemResult - * - * @property int $ID - * @property string $TITLE - * @property string|null $TYPE_ID - * @property string|null $CATEGORY_ID - * @property string $STAGE_ID - * @property string $STAGE_SEMANTIC_ID - * @property string $IS_NEW - * @property string $IS_RECURRING - * @property string|null $PROBABILITY - * @property string $CURRENCY_ID - * @property string $OPPORTUNITY - * @property string $IS_MANUAL_OPPORTUNITY - * @property string $TAX_VALUE - * @property string $LEAD_ID - * @property string $COMPANY_ID - * @property string $CONTACT_ID - * @property string $QUOTE_ID - * @property string $BEGINDATE - * @property string $CLOSEDATE - * @property string $OPENED - * @property string $CLOSED - * @property string|null $COMMENTS - * @property string|null $ADDITIONAL_INFO - * @property string|null $LOCATION_ID - * @property string $IS_RETURN_CUSTOMER - * @property string $IS_REPEATED_APPROACH - * @property int|null $SOURCE_ID - * @property string|null $SOURCE_DESCRIPTION - * @property string|null $ORIGINATOR_ID - * @property string|null $ORIGIN_ID - * @property string|null $UTM_SOURCE - * @property string|null $UTM_MEDIUM - * @property string|null $UTM_CAMPAIGN - * @property string|null $UTM_CONTENT - * @property string|null $UTM_TERM - */ -class DealItemResult extends AbstractItem -{ -} -``` \ No newline at end of file diff --git a/docs/RU/documentation.md b/docs/RU/documentation.md deleted file mode 100644 index 31b70eaa..00000000 --- a/docs/RU/documentation.md +++ /dev/null @@ -1,103 +0,0 @@ -Документация по работе с bitrix24-php-sdk -============================================= - -## Авторизация на портале - -- с использованием [входящих веб-хуков](Core/Auth/auth.md) -- с использованием [OAuth 2.0 токенов](Core/Auth/auth.md#подключение-к-битрикс24-с-использованием-oauth-20) - -## Возвращаемые результаты ApiClient - -- унифицированный объект [Response](Core/Response/response.md) - -## Возвращаемые результаты сервисов - -- унифицированные объекты [Result](Core/Result/result.md) - -## Обработка событий - -При работе с SDK могут возникать события, которые требуется обработать в клиентском коде. Библиотека позволяет подписаться на эти события с -помощью компонента `EventDispatcher` -Список [событий](Core/Events/events.md), на которые можно подписаться. - -## Отправка запросов в пакетном режиме — batch - -- [получение данных](Core/Batch/batch-read-mode.md) в batch-режиме -- запись данных в batch-режиме -- смешанный режим работы - -## Сервисы - -SDK разбита на сервисы которые соответствуют разрешениям — SCOPE к различным сущностям Битрикс24. Каждый сервис расположен в своём -неймспейсе и предоставляет API по работе с методами из своего пространства имён. - -Именно сервис предоставляет CRUD+ API по работе с сущностью. - -- im -- imbot -- bizproc -- placement -- user -- entity -- pull -- pull_channel -- mobile -- log -- sonet_group -- telephony -- call -- messageservice -- forum -- pay_system -- mailservice -- userconsent -- rating -- smile -- lists -- delivery -- sale -- timeman -- faceid -- landing -- landing_cloud -- imopenlines -- calendar -- department -- contact_center -- intranet -- documentgenerator -- crm -- task -- tasks_extended -- disk -- catalog -- rpa -- salescenter -- socialnetwork - -Точкой входа в неймспейс является билдер сервисов. Например — `CRMServiceBuilder`, который производит конфигурацию конкретных сервисов -отвечающих за работу с CRM. - -Сервисы предоставляют CRUD+ API по работе с конкретной сущностью, сервис именуется так же как сущность. Сервис по работе со сделками будет -доступен при вызове `CRM\Deals\Service\Deals` - -## Ключевые тезисы - -1. Результаты возвращаемые SDK *неизменяемые* -2. Результаты работы сервисов типизированы и предоставляют методы для работы с данными конкретной сущности -3. Методы отвечающие за добавление и изменение данных документированы в формате phpstan и предоставляют подсказки по типам данных. -4. Все методы именуются так же, как методы API. - -## Утилиты - -Вместе с SDK поставляется набор CLI-утилит для работы с порталом - -- `benchmark:list` – тест производительности выборки данных для метода *.list в разных режимах работы -- `generate:contacts` – генерация тестовых контактов -- `util:show-fields-description` – показ полей сущности в виде таблицы или в формате phpDoc для аннотирования DTO-объектов результатов - -Показ списка утилит - -```shell -mesilov@mesilov-local bitrix24-php-sdk % php -f tools/bin/console -``` \ No newline at end of file diff --git a/docs/RU/how-to-add-new-scope/new-scope.md b/docs/RU/how-to-add-new-scope/new-scope.md deleted file mode 100644 index d812542e..00000000 --- a/docs/RU/how-to-add-new-scope/new-scope.md +++ /dev/null @@ -1,110 +0,0 @@ -# Добавление (scope telephony) -1. Для начало следует разместить локально сам проект (telephony). -2. Далее следует выполнить команду -``` -composer install -``` - Если при выполнении этой команды вылезли ошибки, то скорее всего следует доставить зависимости. И снова выполнить вышеприведенную команду. -3. Регистрируемся на портале Битрикс 24 и создаем локальное приложение (инструкция по созданию локального приложения находится по пути: `docs/RU/Application/new-local-application.md` ). -4. Далее следует почитать документацию и презентацию. Ссылка на документацию: `https://symfony.com/doc/current/http_client.html`, презентация называется `The_Modern_And_Fast_HttpClient` и ее можно легко найти в интернете. -5. В папке `src/Services` размещаем наш скоуп с Телефонией. - 1. Создаем две папки Result и Service - 2. В папке Service будут размещены сервисы с их методами. - 1. Для примера создадим сервис ExternalLine с одним из методов. - ```php - core->call( - 'telephony.externalLine.add', - [ - 'NUMBER' => $lineNumber, - 'NAME' => $nameLine, - ] - )); - } - ``` - 3. В папке Result будут размещены результаты наших методов(то что они будут возвращать). - 1. Для примера создадим ExternalLineAddResult.php - ```php - getCoreResponse()->getResponseData()->getResult()->getResultData()['ID']; - } - - } - 4. Также в папке `src/Services/(название вашего сервиса)` размещаем (название вашего сервиса)ServiceBuilder.php. Этот сервис нужен для подключения нашего скоупа с тестами. -6. После того как мы добавили наши методы для работы с Телефонией нужно их затестить. Создадим в папке `tests/Integration/Services/Telephony/Service/` наши тесты и проверим все ли работает как надо ExternalLineTest.php. - ```php - externalLineService->add((string)time(), sprintf('phpUnit-%s', time()))->getId()); - } - /** - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException - */ - public function setUp(): void - { - $this->externalLineService = Fabric::getServiceBuilder()->getTelephonyScope()->externalline(); - } - } - ``` \ No newline at end of file From 1494ffe96660383ddf6e1e83579100aa9a02b82b Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 5 Jul 2024 01:48:14 +0600 Subject: [PATCH 077/138] Add Bitrix24AccountRepositoryInterface and update exceptions in Bitrix24AccountInterface A new file, Bitrix24AccountRepositoryInterface, has been created which defines the methods to interact with Bitrix24 account data in a data store. Additionally, the Bitrix24AccountInterface has been updated to throw an InvalidArgumentException where needed to make error handling more explicit and robust. Signed-off-by: mesilov --- .../Entity/Bitrix24AccountInterface.php | 8 ++++++- .../Bitrix24AccountRepositoryInterface.php | 22 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 src/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterface.php diff --git a/src/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterface.php b/src/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterface.php index 5eee782f..2c13a192 100644 --- a/src/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterface.php +++ b/src/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterface.php @@ -6,6 +6,7 @@ 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; @@ -71,11 +72,13 @@ 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; @@ -100,20 +103,23 @@ public function getUpdatedAt(): CarbonImmutable; /** * Update application version if application was updated in marketplace * - * @param int $version application version from 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; diff --git a/src/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterface.php b/src/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterface.php new file mode 100644 index 00000000..68b73f66 --- /dev/null +++ b/src/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterface.php @@ -0,0 +1,22 @@ + Date: Fri, 5 Jul 2024 01:56:00 +0600 Subject: [PATCH 078/138] Rename AccessToken to AuthToken and refactor related codes The AccessToken class has been renamed to AuthToken. This was accompanied by the renaming and modification of related methods, variables, and usages across multiple files. A new file was created, RenewedAuthToken.php, while the old RenewedAccessToken.php was deleted. WebhookUrl usage has also been adjusted. Signed-off-by: mesilov --- src/Core/ApiClient.php | 26 ++++---- src/Core/Contracts/ApiClientInterface.php | 4 +- src/Core/Core.php | 26 ++++---- .../{AccessToken.php => AuthToken.php} | 18 ++--- src/Core/Credentials/Credentials.php | 18 ++--- src/Core/Response/DTO/RenewedAccessToken.php | 66 ------------------- src/Core/Response/DTO/RenewedAuthToken.php | 45 +++++++++++++ src/Events/AuthTokenRenewedEvent.php | 18 ++--- 8 files changed, 97 insertions(+), 124 deletions(-) rename src/Core/Credentials/{AccessToken.php => AuthToken.php} (84%) delete mode 100644 src/Core/Response/DTO/RenewedAccessToken.php create mode 100644 src/Core/Response/DTO/RenewedAuthToken.php diff --git a/src/Core/ApiClient.php b/src/Core/ApiClient.php index 289589fd..dc1f6b69 100644 --- a/src/Core/ApiClient.php +++ b/src/Core/ApiClient.php @@ -5,10 +5,12 @@ 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\RenewedAccessToken; +use Bitrix24\SDK\Core\Response\DTO\RenewedAuthToken; use Bitrix24\SDK\Infrastructure\HttpClient\RequestId\RequestIdGeneratorInterface; use Fig\Http\Message\StatusCodeInterface; use Psr\Log\LoggerInterface; @@ -71,17 +73,17 @@ public function getCredentials(): Credentials * @throws TransportExceptionInterface * @throws TransportException */ - public function getNewAccessToken(): RenewedAccessToken + public function getNewAuthToken(): RenewedAuthToken { $requestId = $this->requestIdGenerator->getRequestId(); - $this->logger->debug('getNewAccessToken.start', [ + $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()->getAccessToken() instanceof \Bitrix24\SDK\Core\Credentials\AccessToken) { + if (!$this->getCredentials()->getAuthToken() instanceof AuthToken) { throw new InvalidArgumentException('access token in credentials not set'); } @@ -94,7 +96,7 @@ public function getNewAccessToken(): RenewedAccessToken 'grant_type' => 'refresh_token', 'client_id' => $this->getCredentials()->getApplicationProfile()->getClientId(), 'client_secret' => $this->getCredentials()->getApplicationProfile()->getClientSecret(), - 'refresh_token' => $this->getCredentials()->getAccessToken()->getRefreshToken(), + 'refresh_token' => $this->getCredentials()->getAuthToken()->getRefreshToken(), $this->requestIdGenerator->getQueryStringParameterName() => $requestId ] ) @@ -111,16 +113,16 @@ public function getNewAccessToken(): RenewedAccessToken $response = $this->client->request($method, $url, $requestOptions); $responseData = $response->toArray(false); if ($response->getStatusCode() === StatusCodeInterface::STATUS_OK) { - $newAccessToken = RenewedAccessToken::initFromArray($responseData); + $newAuthToken = RenewedAuthToken::initFromArray($responseData); - $this->logger->debug('getNewAccessToken.finish', [ + $this->logger->debug('getNewAuthToken.finish', [ 'requestId' => $requestId ]); - return $newAccessToken; + return $newAuthToken; } if ($response->getStatusCode() === StatusCodeInterface::STATUS_BAD_REQUEST) { - $this->logger->warning('getNewAccessToken.badRequest',[ + $this->logger->warning('getNewAuthToken.badRequest',[ 'url'=> $url ]); throw new TransportException(sprintf('getting new access token failure: %s', $responseData['error'])); @@ -149,16 +151,16 @@ public function getResponse(string $apiMethod, array $parameters = []): Response ); $method = 'POST'; - if ($this->getCredentials()->getWebhookUrl() instanceof \Bitrix24\SDK\Core\Credentials\WebhookUrl) { + 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()->getAccessToken() instanceof \Bitrix24\SDK\Core\Credentials\AccessToken) { + if (!$this->getCredentials()->getAuthToken() instanceof AuthToken) { throw new InvalidArgumentException('access token in credentials not found '); } - $parameters['auth'] = $this->getCredentials()->getAccessToken()->getAccessToken(); + $parameters['auth'] = $this->getCredentials()->getAuthToken()->getAccessToken(); } // duplicate request id in query string for current version of bitrix24 api diff --git a/src/Core/Contracts/ApiClientInterface.php b/src/Core/Contracts/ApiClientInterface.php index 11903492..f1e52855 100644 --- a/src/Core/Contracts/ApiClientInterface.php +++ b/src/Core/Contracts/ApiClientInterface.php @@ -6,7 +6,7 @@ use Bitrix24\SDK\Core\Credentials\Credentials; use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; -use Bitrix24\SDK\Core\Response\DTO\RenewedAccessToken; +use Bitrix24\SDK\Core\Response\DTO\RenewedAuthToken; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Symfony\Contracts\HttpClient\ResponseInterface; @@ -22,7 +22,7 @@ public function getResponse(string $apiMethod, array $parameters = []): Response * @throws InvalidArgumentException * @throws TransportExceptionInterface */ - public function getNewAccessToken(): RenewedAccessToken; + public function getNewAuthToken(): RenewedAuthToken; public function getCredentials(): Credentials; } \ No newline at end of file diff --git a/src/Core/Core.php b/src/Core/Core.php index bbbe7ef6..169d1020 100644 --- a/src/Core/Core.php +++ b/src/Core/Core.php @@ -20,17 +20,13 @@ use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; -/** - * Class Core - * - * @package Bitrix24\SDK\Core - */ class Core implements CoreInterface { - /** - * Main constructor. - */ - public function __construct(protected ApiClientInterface $apiClient, protected ApiLevelErrorHandler $apiLevelErrorHandler, protected EventDispatcherInterface $eventDispatcher, protected LoggerInterface $logger) + public function __construct( + protected ApiClientInterface $apiClient, + protected ApiLevelErrorHandler $apiLevelErrorHandler, + protected EventDispatcherInterface $eventDispatcher, + protected LoggerInterface $logger) { } @@ -109,17 +105,17 @@ public function call(string $apiMethod, array $parameters = []): Response switch (strtolower((string)$body['error'])) { case 'expired_token': // renew access token - $renewedToken = $this->apiClient->getNewAccessToken(); + $renewedToken = $this->apiClient->getNewAuthToken(); $this->logger->debug( 'access token renewed', [ - 'newAccessToken' => $renewedToken->getAccessToken()->getAccessToken(), - 'newRefreshToken' => $renewedToken->getAccessToken()->getRefreshToken(), - 'newExpires' => $renewedToken->getAccessToken()->getExpires(), - 'appStatus' => $renewedToken->getApplicationStatus(), + 'newAccessToken' => $renewedToken->authToken->getAccessToken(), + 'newRefreshToken' => $renewedToken->authToken->getRefreshToken(), + 'newExpires' => $renewedToken->authToken->getExpires(), + 'appStatus' => $renewedToken->applicationStatus->getStatusCode(), ] ); - $this->apiClient->getCredentials()->setAccessToken($renewedToken->getAccessToken()); + $this->apiClient->getCredentials()->setAuthToken($renewedToken->authToken); // repeat api-call $response = $this->call($apiMethod, $parameters); diff --git a/src/Core/Credentials/AccessToken.php b/src/Core/Credentials/AuthToken.php similarity index 84% rename from src/Core/Credentials/AccessToken.php rename to src/Core/Credentials/AuthToken.php index ebb02d3c..9ea72d7d 100644 --- a/src/Core/Credentials/AccessToken.php +++ b/src/Core/Credentials/AuthToken.php @@ -5,15 +5,15 @@ namespace Bitrix24\SDK\Core\Credentials; use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; -use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation; -class AccessToken +class AuthToken { - /** - * AccessToken constructor. - */ - public function __construct(protected string $accessToken, protected ?string $refreshToken, protected int $expires, protected ?int $expiresIn = null) + public function __construct( + protected string $accessToken, + protected ?string $refreshToken, + protected int $expires, + protected ?int $expiresIn = null) { } @@ -47,7 +47,7 @@ public function hasExpired(): bool return $this->getExpires() <= time(); } - + public static function initFromArray(array $request): self { return new self( @@ -57,13 +57,13 @@ public static function initFromArray(array $request): self ); } - public static function initFromWorkflowRequest(Request $request): self + public static function initFromWorkflowRequest(HttpFoundation\Request $request): self { $requestFields = $request->request->all(); return self::initFromArray($requestFields['auth']); } - public static function initFromEventRequest(Request $request): self + public static function initFromEventRequest(HttpFoundation\Request $request): self { $requestFields = $request->request->all(); return new self( diff --git a/src/Core/Credentials/Credentials.php b/src/Core/Credentials/Credentials.php index 9adae014..bb9d9abe 100644 --- a/src/Core/Credentials/Credentials.php +++ b/src/Core/Credentials/Credentials.php @@ -16,7 +16,7 @@ class Credentials */ public function __construct( protected ?WebhookUrl $webhookUrl, - protected ?AccessToken $accessToken, + protected ?AuthToken $authToken, protected ?ApplicationProfile $applicationProfile, ?string $domainUrl ) @@ -25,18 +25,18 @@ public function __construct( $this->setDomainUrl($domainUrl); } - if (!$this->accessToken instanceof AccessToken && !$this->webhookUrl instanceof WebhookUrl) { + 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->accessToken instanceof AccessToken && $this->domainUrl === null) { + if ($this->authToken instanceof AuthToken && $this->domainUrl === null) { throw new InvalidArgumentException('for oauth type you must set domain url'); } } - public function setAccessToken(AccessToken $accessToken): void + public function setAuthToken(AuthToken $authToken): void { - $this->accessToken = $accessToken; + $this->authToken = $authToken; } /** @@ -61,7 +61,7 @@ public function setDomainUrl(string $domainUrl): void public function isWebhookContext(): bool { - return $this->webhookUrl instanceof WebhookUrl && !$this->accessToken instanceof AccessToken; + return $this->webhookUrl instanceof WebhookUrl && !$this->authToken instanceof AuthToken; } public function getApplicationProfile(): ?ApplicationProfile @@ -81,9 +81,9 @@ public function getWebhookUrl(): ?WebhookUrl return $this->webhookUrl; } - public function getAccessToken(): ?AccessToken + public function getAuthToken(): ?AuthToken { - return $this->accessToken; + return $this->authToken; } /** @@ -103,7 +103,7 @@ public static function createFromWebhook(WebhookUrl $webhookUrl): self * * @throws InvalidArgumentException */ - public static function createFromOAuth(AccessToken $accessToken, ApplicationProfile $applicationProfile, string $domainUrl): self + public static function createFromOAuth(AuthToken $accessToken, ApplicationProfile $applicationProfile, string $domainUrl): self { return new self( null, diff --git a/src/Core/Response/DTO/RenewedAccessToken.php b/src/Core/Response/DTO/RenewedAccessToken.php deleted file mode 100644 index 9b1cbde3..00000000 --- a/src/Core/Response/DTO/RenewedAccessToken.php +++ /dev/null @@ -1,66 +0,0 @@ -accessToken; - } - - public function getMemberId(): string - { - return $this->memberId; - } - - public function getClientEndpoint(): string - { - return $this->clientEndpoint; - } - - public function getServerEndpoint(): string - { - return $this->serverEndpoint; - } - - public function getApplicationStatus(): string - { - return $this->applicationStatus; - } - - public function getDomain(): string - { - return $this->domain; - } - - public static function initFromArray(array $response): self - { - return new self( - AccessToken::initFromArray($response), - (string)$response['member_id'], - (string)$response['client_endpoint'], - (string)$response['server_endpoint'], - (string)$response['status'], - (string)$response['domain'] - ); - } -} \ 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..56965113 --- /dev/null +++ b/src/Core/Response/DTO/RenewedAuthToken.php @@ -0,0 +1,45 @@ +renewedToken = $renewedToken; } /** - * @return RenewedAccessToken + * @return RenewedAuthToken */ - public function getRenewedToken(): RenewedAccessToken + public function getRenewedToken(): RenewedAuthToken { return $this->renewedToken; } From a8cd3aeb71fd6b5cb94cd3deb4828430aea9958e Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 5 Jul 2024 01:59:17 +0600 Subject: [PATCH 079/138] Update import paths and references in ServiceBuilderFactory This commit adjusts various import paths in the ServiceBuilderFactory class and updates the corresponding references in the code. The AccessToken import and references have been changed to AuthToken. The Bitrix24AccountInterface has been moved to another directory and the changes have been reflected. Certain use statements for exceptions have also been added. Signed-off-by: mesilov --- src/Services/ServiceBuilderFactory.php | 50 +++++++++++++------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/Services/ServiceBuilderFactory.php b/src/Services/ServiceBuilderFactory.php index 5bef3253..0609ccf5 100644 --- a/src/Services/ServiceBuilderFactory.php +++ b/src/Services/ServiceBuilderFactory.php @@ -4,14 +4,15 @@ namespace Bitrix24\SDK\Services; -use Bitrix24\SDK\Application\Contracts\Bitrix24Account\Bitrix24AccountInterface; +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\AccessToken; +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\Component\EventDispatcher\EventDispatcherInterface; @@ -21,8 +22,8 @@ class ServiceBuilderFactory private LoggerInterface $log; /** - * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $eventDispatcher - * @param \Psr\Log\LoggerInterface $log + * @param EventDispatcherInterface $eventDispatcher + * @param LoggerInterface $log */ public function __construct(EventDispatcherInterface $eventDispatcher, LoggerInterface $log) { @@ -33,21 +34,21 @@ public function __construct(EventDispatcherInterface $eventDispatcher, LoggerInt /** * Init service builder from application account * - * @param ApplicationProfile $applicationProfile + * @param ApplicationProfile $applicationProfile * @param Bitrix24AccountInterface $bitrix24Account * - * @return \Bitrix24\SDK\Services\ServiceBuilder - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @return ServiceBuilder + * @throws InvalidArgumentException */ public function initFromAccount(ApplicationProfile $applicationProfile, Bitrix24AccountInterface $bitrix24Account): ServiceBuilder { return $this->getServiceBuilder( Credentials::createFromOAuth( - AccessToken::initFromArray( + AuthToken::initFromArray( [ - 'access_token' => $bitrix24Account->getAccessToken(), - 'refresh_token' => $bitrix24Account->getRefreshToken(), - 'expires' => $bitrix24Account->getExpires(), + 'access_token' => $bitrix24Account->getAuthToken()->getAccessToken(), + 'refresh_token' => $bitrix24Account->getAuthToken()->getRefreshToken(), + 'expires' => $bitrix24Account->getAuthToken()->getExpires(), ] ), $applicationProfile, @@ -59,18 +60,19 @@ public function initFromAccount(ApplicationProfile $applicationProfile, Bitrix24 /** * Init service builder from request * - * @param \Bitrix24\SDK\Core\Credentials\ApplicationProfile $applicationProfile - * @param \Bitrix24\SDK\Core\Credentials\AccessToken $accessToken - * @param string $bitrix24DomainUrl + * @param ApplicationProfile $applicationProfile + * @param AuthToken $accessToken + * @param string $bitrix24DomainUrl * - * @return \Bitrix24\SDK\Services\ServiceBuilder - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @return ServiceBuilder + * @throws InvalidArgumentException */ public function initFromRequest( ApplicationProfile $applicationProfile, - AccessToken $accessToken, - string $bitrix24DomainUrl - ): ServiceBuilder { + AuthToken $accessToken, + string $bitrix24DomainUrl + ): ServiceBuilder + { return $this->getServiceBuilder( Credentials::createFromOAuth( $accessToken, @@ -85,8 +87,8 @@ public function initFromRequest( * * @param string $webhookUrl * - * @return \Bitrix24\SDK\Services\ServiceBuilder - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @return ServiceBuilder + * @throws InvalidArgumentException */ public function initFromWebhook(string $webhookUrl): ServiceBuilder { @@ -94,10 +96,10 @@ public function initFromWebhook(string $webhookUrl): ServiceBuilder } /** - * @param \Bitrix24\SDK\Core\Credentials\Credentials $credentials + * @param Credentials $credentials * - * @return \Bitrix24\SDK\Services\ServiceBuilder - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException + * @return ServiceBuilder + * @throws InvalidArgumentException */ private function getServiceBuilder(Credentials $credentials): ServiceBuilder { From 9a8c29794bca2f95992c2a45328c9e40a5cb6ed4 Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 5 Jul 2024 02:02:38 +0600 Subject: [PATCH 080/138] Replace AccessToken with AuthToken The AccessToken class has been replaced with the AuthToken class across several modules. This includes changes in method arguments, object initializations, and class properties. The goal is to maintain consistency throughout the application by using the newly introduced AuthToken class. Signed-off-by: mesilov --- .../Requests/Placement/PlacementRequest.php | 10 +++++----- src/Services/ServiceBuilderFactory.php | 8 +------- src/Services/Workflows/Common/Auth.php | 6 +++--- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/Application/Requests/Placement/PlacementRequest.php b/src/Application/Requests/Placement/PlacementRequest.php index 99e3fb7c..27d0c9ec 100644 --- a/src/Application/Requests/Placement/PlacementRequest.php +++ b/src/Application/Requests/Placement/PlacementRequest.php @@ -5,14 +5,14 @@ namespace Bitrix24\SDK\Application\Requests\Placement; use Bitrix24\SDK\Application\ApplicationStatus; -use Bitrix24\SDK\Core\Credentials\AccessToken; +use Bitrix24\SDK\Core\Credentials\AuthToken; use Bitrix24\SDK\Application\Requests\AbstractRequest; use InvalidArgumentException; use Symfony\Component\HttpFoundation\Request; class PlacementRequest extends AbstractRequest { - private AccessToken $accessToken; + private AuthToken $accessToken; private string $memberId; private ApplicationStatus $applicationStatus; private string $code; @@ -38,7 +38,7 @@ public function __construct(Request $request) $this->domainUrl = sprintf('https://%s', $queryArgs['DOMAIN']); $this->languageCode = $queryArgs['LANG']; - $this->accessToken = AccessToken::initFromPlacementRequest($request); + $this->accessToken = AuthToken::initFromPlacementRequest($request); $this->applicationStatus = ApplicationStatus::initFromRequest($request); $this->memberId = $request->request->get('member_id'); $this->code = (string)$request->request->get('PLACEMENT'); @@ -68,9 +68,9 @@ public function getMemberId(): string } /** - * @return \Bitrix24\SDK\Core\Credentials\AccessToken + * @return \Bitrix24\SDK\Core\Credentials\AuthToken */ - public function getAccessToken(): AccessToken + public function getAccessToken(): AuthToken { return $this->accessToken; } diff --git a/src/Services/ServiceBuilderFactory.php b/src/Services/ServiceBuilderFactory.php index 0609ccf5..3a19848c 100644 --- a/src/Services/ServiceBuilderFactory.php +++ b/src/Services/ServiceBuilderFactory.php @@ -44,13 +44,7 @@ public function initFromAccount(ApplicationProfile $applicationProfile, Bitrix24 { return $this->getServiceBuilder( Credentials::createFromOAuth( - AuthToken::initFromArray( - [ - 'access_token' => $bitrix24Account->getAuthToken()->getAccessToken(), - 'refresh_token' => $bitrix24Account->getAuthToken()->getRefreshToken(), - 'expires' => $bitrix24Account->getAuthToken()->getExpires(), - ] - ), + $bitrix24Account->getAuthToken(), $applicationProfile, $bitrix24Account->getDomainUrl() ) diff --git a/src/Services/Workflows/Common/Auth.php b/src/Services/Workflows/Common/Auth.php index 1c1bfde9..be50a388 100644 --- a/src/Services/Workflows/Common/Auth.php +++ b/src/Services/Workflows/Common/Auth.php @@ -5,7 +5,7 @@ namespace Bitrix24\SDK\Services\Workflows\Common; use Bitrix24\SDK\Application\ApplicationStatus; -use Bitrix24\SDK\Core\Credentials\AccessToken; +use Bitrix24\SDK\Core\Credentials\AuthToken; use Bitrix24\SDK\Core\Credentials\Endpoints; use Bitrix24\SDK\Core\Credentials\Scope; use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; @@ -14,7 +14,7 @@ readonly class Auth { public function __construct( - public AccessToken $accessToken, + public AuthToken $accessToken, public Endpoints $endpoints, public Scope $scope, public ApplicationStatus $applicationStatus, @@ -34,7 +34,7 @@ public function __construct( public static function initFromArray(array $auth): self { return new self( - AccessToken::initFromArray($auth), + AuthToken::initFromArray($auth), Endpoints::initFromArray($auth), Scope::initFromString($auth['scope']), ApplicationStatus::initFromString($auth['status']), From 757a7aa8f387501861eccceffe259eb342c2eea4 Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 5 Jul 2024 02:03:32 +0600 Subject: [PATCH 081/138] Replace AccessToken with AuthToken in tests The code changes replace the usage of AccessToken with AuthToken in the Core and Credentials test files. The AccessToken class is replaced globally with the AuthToken class to reflect changes or improvements in the authorization process. Signed-off-by: mesilov --- tests/Integration/Core/CoreTest.php | 4 ++-- tests/Unit/Core/Credentials/CredentialsTest.php | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/Integration/Core/CoreTest.php b/tests/Integration/Core/CoreTest.php index becfb839..1c541897 100644 --- a/tests/Integration/Core/CoreTest.php +++ b/tests/Integration/Core/CoreTest.php @@ -6,7 +6,7 @@ use Bitrix24\SDK\Core\Contracts\CoreInterface; use Bitrix24\SDK\Core\CoreBuilder; -use Bitrix24\SDK\Core\Credentials\AccessToken; +use Bitrix24\SDK\Core\Credentials\AuthToken; use Bitrix24\SDK\Core\Credentials\ApplicationProfile; use Bitrix24\SDK\Core\Credentials\Credentials; use Bitrix24\SDK\Core\Credentials\Scope; @@ -39,7 +39,7 @@ public function testConnectToNonExistsBitrix24PortalInCloud():void $core = (new CoreBuilder()) ->withLogger($this->log) ->withCredentials(Credentials::createFromOAuth( - new AccessToken('non-exists-access-token','refresh-token', 3600), + 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' )) diff --git a/tests/Unit/Core/Credentials/CredentialsTest.php b/tests/Unit/Core/Credentials/CredentialsTest.php index 65b4ab94..827f732f 100644 --- a/tests/Unit/Core/Credentials/CredentialsTest.php +++ b/tests/Unit/Core/Credentials/CredentialsTest.php @@ -4,7 +4,7 @@ namespace Bitrix24\SDK\Tests\Unit\Core\Credentials; -use Bitrix24\SDK\Core\Credentials\AccessToken; +use Bitrix24\SDK\Core\Credentials\AuthToken; use Bitrix24\SDK\Core\Credentials\ApplicationProfile; use Bitrix24\SDK\Core\Credentials\Credentials; use Bitrix24\SDK\Core\Credentials\Scope; @@ -40,7 +40,7 @@ public function testGetDomainUrl( public function testDomainUrlWithoutProtocol(): void { $credentials = Credentials::createFromOAuth( - new AccessToken('', '', 0), + new AuthToken('', '', 0), new ApplicationProfile('', '', new Scope(['crm'])), 'bitrix24-php-sdk-playground.bitrix24.ru' ); @@ -54,7 +54,7 @@ public function testDomainUrlWithoutProtocol(): void public function testIsWebhookContext():void { $credentials = Credentials::createFromOAuth( - new AccessToken('', '', 0), + new AuthToken('', '', 0), new ApplicationProfile('', '', new Scope(['crm'])), 'bitrix24-php-sdk-playground.bitrix24.ru' ); @@ -71,7 +71,7 @@ public function testIsWebhookContext():void public function testDomainUrlWithProtocol(): void { $credentials = Credentials::createFromOAuth( - new AccessToken('', '', 0), + new AuthToken('', '', 0), new ApplicationProfile('', '', new Scope(['crm'])), 'https://bitrix24-php-sdk-playground.bitrix24.ru' ); @@ -94,7 +94,7 @@ public static function credentialsDataProviderWithDomainUrlVariants(): Generator ]; yield 'with oauth domain url with end /' => [ Credentials::createFromOAuth( - new AccessToken('', '', 0), + new AuthToken('', '', 0), new ApplicationProfile('', '', new Scope(['crm'])), 'https://bitrix24-php-sdk-playground.bitrix24.ru/' ), @@ -102,7 +102,7 @@ public static function credentialsDataProviderWithDomainUrlVariants(): Generator ]; yield 'with oauth domain url without end /' => [ Credentials::createFromOAuth( - new AccessToken('', '', 0), + new AuthToken('', '', 0), new ApplicationProfile('', '', new Scope(['crm'])), 'https://bitrix24-php-sdk-playground.bitrix24.ru' ), From 26e3a3443a86ca182608e04d2cb245802ae8bace Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 5 Jul 2024 02:06:18 +0600 Subject: [PATCH 082/138] Refactor authToken parameters in Core classes The authToken parameters in the Core classes 'RenewedAuthToken' and 'Credentials' have been refactored. In 'RenewedAuthToken', unnecessary authToken and applicationStatus parameters were removed. In 'Credentials', variable name 'accessToken' was changed to 'authToken' for consistency and clarity. Signed-off-by: mesilov --- src/Core/Credentials/Credentials.php | 4 ++-- src/Core/Response/DTO/RenewedAuthToken.php | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Core/Credentials/Credentials.php b/src/Core/Credentials/Credentials.php index bb9d9abe..3398104a 100644 --- a/src/Core/Credentials/Credentials.php +++ b/src/Core/Credentials/Credentials.php @@ -103,11 +103,11 @@ public static function createFromWebhook(WebhookUrl $webhookUrl): self * * @throws InvalidArgumentException */ - public static function createFromOAuth(AuthToken $accessToken, ApplicationProfile $applicationProfile, string $domainUrl): self + public static function createFromOAuth(AuthToken $authToken, ApplicationProfile $applicationProfile, string $domainUrl): self { return new self( null, - $accessToken, + $authToken, $applicationProfile, $domainUrl ); diff --git a/src/Core/Response/DTO/RenewedAuthToken.php b/src/Core/Response/DTO/RenewedAuthToken.php index 56965113..88c6ce88 100644 --- a/src/Core/Response/DTO/RenewedAuthToken.php +++ b/src/Core/Response/DTO/RenewedAuthToken.php @@ -11,11 +11,9 @@ readonly class RenewedAuthToken { /** - * @param AuthToken $authToken * @param non-empty-string $memberId * @param non-empty-string $clientEndpoint * @param non-empty-string $serverEndpoint - * @param ApplicationStatus $applicationStatus * @param non-empty-string $domain */ public function __construct( From b60fbd1f8f81833294fb4eba0ee9895601ea7255 Mon Sep 17 00:00:00 2001 From: mesilov Date: Fri, 5 Jul 2024 02:07:28 +0600 Subject: [PATCH 083/138] Add Bitrix24AccountInterface test entity implementation A new file containing a test implementation of the Bitrix24AccountInterface has been added, which includes methods for checking user status, managing authentication tokens, updating domain URL, and handling application installation and upgrade cases. The created tests help ensure the functionality and reliability of the system with Bitrix24Accounts. Signed-off-by: mesilov --- ...countInterfaceTestEntityImplementation.php | 254 ++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTestEntityImplementation.php diff --git a/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTestEntityImplementation.php b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTestEntityImplementation.php new file mode 100644 index 00000000..f8ed5c6a --- /dev/null +++ b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTestEntityImplementation.php @@ -0,0 +1,254 @@ +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->getMemberId() !== $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->getMemberId(), + $this->getId()->toRfc4122(), + $this->getDomainUrl(), + $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; + } + + 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('new account must be in status new'); + } + 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 ($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 !== null) { + $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::active; + $this->comment = $comment; + $this->updatedAt = new CarbonImmutable(); + } + + public function getComment(): ?string + { + return $this->comment; + } +} \ No newline at end of file From c8612c96ecc9000593c4a8bf19c6b78273ec660f Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 6 Jul 2024 09:07:03 +0600 Subject: [PATCH 084/138] Update bitrix24 account interface and other related tests Renamed the testing and reference implementation classes of Bitrix24AccountInterface and adjusted the methods due to changes in their behavior. Also added new methods for ApplicationStatus testing. This refactoring is important to ensure accurate testing and representation of our Bitrix24Accounts and their statuses. Signed-off-by: mesilov --- src/Application/ApplicationStatus.php | 30 + .../Application/ApplicationStatusTest.php | 30 + ...ntInterfaceReferenceImplementationTest.php | 48 ++ .../Entity/Bitrix24AccountInterfaceTest.php | 539 ++++++++++++++++++ ...4AccountReferenceEntityImplementation.php} | 19 +- 5 files changed, 660 insertions(+), 6 deletions(-) create mode 100644 tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceReferenceImplementationTest.php create mode 100644 tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php rename tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/{Bitrix24AccountInterfaceTestEntityImplementation.php => Bitrix24AccountReferenceEntityImplementation.php} (89%) diff --git a/src/Application/ApplicationStatus.php b/src/Application/ApplicationStatus.php index 94662f48..65352c03 100644 --- a/src/Application/ApplicationStatus.php +++ b/src/Application/ApplicationStatus.php @@ -37,6 +37,11 @@ public function __construct(string $statusShortCode) }; } + public static function free(): self + { + return new self(self::STATUS_SHORT_FREE); + } + /** * @return bool */ @@ -53,6 +58,11 @@ public function isDemo(): bool return 'demo' === $this->statusCode; } + public static function demo(): self + { + return new self(self::STATUS_SHORT_DEMO); + } + /** * @return bool */ @@ -61,6 +71,11 @@ public function isTrial(): bool return 'trial' === $this->statusCode; } + public static function trial(): self + { + return new self(self::STATUS_SHORT_TRIAL); + } + /** * @return bool */ @@ -69,6 +84,11 @@ public function isPaid(): bool return 'paid' === $this->statusCode; } + public static function paid(): self + { + return new self(self::STATUS_SHORT_PAID); + } + /** * @return bool */ @@ -77,6 +97,11 @@ public function isLocal(): bool return 'local' === $this->statusCode; } + public static function local(): self + { + return new self(self::STATUS_SHORT_LOCAL); + } + /** * @return bool */ @@ -85,6 +110,11 @@ public function isSubscription(): bool return 'subscription' === $this->statusCode; } + public static function subscription(): self + { + return new self(self::STATUS_SHORT_SUBSCRIPTION); + } + /** * @return string */ diff --git a/tests/Unit/Application/ApplicationStatusTest.php b/tests/Unit/Application/ApplicationStatusTest.php index ba6214ce..5d1a16b3 100644 --- a/tests/Unit/Application/ApplicationStatusTest.php +++ b/tests/Unit/Application/ApplicationStatusTest.php @@ -46,6 +46,36 @@ 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()->isLocal()); + } + /** * @return \Generator */ 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..0d4ad60c --- /dev/null +++ b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceReferenceImplementationTest.php @@ -0,0 +1,48 @@ +createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertEquals($id, $ob->getId()); + } + + #[Test] + #[DataProvider('bitrix24AccountDataProvider')] + #[TestDox('test getBitrix24UserId method')] + final public function testGetBitrix24UserId( + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertEquals($bitrix24UserId, $ob->getBitrix24UserId()); + } + + #[Test] + #[DataProvider('bitrix24AccountDataProvider')] + #[TestDox('test isBitrix24UserAdmin method')] + final public function testisBitrix24UserAdmin( + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertEquals($isBitrix24UserAdmin, $ob->isBitrix24UserAdmin()); + } + + #[Test] + #[DataProvider('bitrix24AccountDataProvider')] + #[TestDox('test getMemberId method')] + final public function testGetMemberId( + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertEquals($memberId, $ob->getMemberId()); + } + + #[Test] + #[DataProvider('bitrix24AccountDataProvider')] + #[TestDox('test getDomainUrl method')] + final public function testGetDomainUrl( + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertEquals($domainUrl, $ob->getDomainUrl()); + } + + #[Test] + #[DataProvider('bitrix24AccountDataProvider')] + #[TestDox('test getStatus method')] + final public function testGetStatus( + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertEquals($accountStatus, $ob->getStatus()); + } + + #[Test] + #[DataProvider('bitrix24AccountDataProvider')] + #[TestDox('test getAuthToken method')] + final public function testGetAuthToken( + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertEquals($authToken, $ob->getAuthToken()); + } + + #[Test] + #[DataProvider('bitrix24AccountDataProvider')] + #[TestDox('test renewAuthToken method')] + final public function testRenewAuthToken( + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $newAuthToken = new AuthToken('access_token-2', 'refresh_token=2', 1609459202); + $appStatus = ApplicationStatus::subscription(); + + $renewedAuthToken = new RenewedAuthToken( + $newAuthToken, + $memberId, + 'https://bitrix24.com/client', + 'https://bitrix24.com/server', + $appStatus, + $domainUrl + ); + $ob->renewAuthToken($renewedAuthToken); + + + $this->assertEquals($newAuthToken, $ob->getAuthToken()); + } + + #[Test] + #[DataProvider('bitrix24AccountDataProvider')] + #[TestDox('test getApplicationVersion method')] + final public function testGetApplicationVersion( + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertEquals($applicationVersion, $ob->getApplicationVersion()); + } + + + #[Test] + #[DataProvider('bitrix24AccountDataProvider')] + #[TestDox('test getApplicationScope method')] + final public function testGetApplicationScope( + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertEquals($applicationScope, $ob->getApplicationScope()); + } + + #[Test] + #[DataProvider('bitrix24AccountDataProvider')] + #[TestDox('test changeDomainUrl method')] + final public function testChangeDomainUrl( + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $newDomainUrl = 'new-bitrix24.com'; + $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $ob->changeDomainUrl($newDomainUrl); + $this->assertEquals($newDomainUrl, $ob->getDomainUrl()); + } + + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test applicationInstalled method')] + final public function testApplicationInstalled( + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope, + string $applicationToken, + ?Throwable $exception + ): void + { + if ($exception !== null) { + $this->expectException($exception::class); + } + $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $ob->applicationInstalled($applicationToken); + $this->assertTrue($ob->isApplicationTokenValid($applicationToken)); + } + + #[Test] + #[DataProvider('bitrix24AccountForUninstallDataProvider')] + #[TestDox('test applicationUninstalled method')] + final public function testApplicationUninstalled( + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatusForInstall, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope, + string $applicationToken, + ?Throwable $exception + ): void + { + if ($exception !== null) { + $this->expectException($exception::class); + } + $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatusForInstall, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $ob->applicationInstalled($applicationToken); + $ob->applicationUninstalled($applicationToken); + $this->assertEquals(Bitrix24AccountStatus::deleted, $ob->getStatus()); + } + + 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() + ]; + } + + 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/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTestEntityImplementation.php b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountReferenceEntityImplementation.php similarity index 89% rename from tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTestEntityImplementation.php rename to tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountReferenceEntityImplementation.php index f8ed5c6a..d8b007f0 100644 --- a/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTestEntityImplementation.php +++ b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountReferenceEntityImplementation.php @@ -14,19 +14,19 @@ use Symfony\Component\Uid\Uuid; /** - * Class Bitrix24AccountInterfaceTestEntityImplementation + * Class Bitrix24AccountReferenceEntityImplementation * - * This class use for test interface and use cases for work with Bitrix24AccountInterface methods + * This class uses ONLY for demonstration and tests interface, use cases for work with Bitrix24AccountInterface methods * * @implements Bitrix24AccountInterface */ -final class Bitrix24AccountInterfaceTestEntityImplementation implements Bitrix24AccountInterface +final class Bitrix24AccountReferenceEntityImplementation implements Bitrix24AccountInterface { private string $accessToken; private string $refreshToken; private int $expires; private array $applicationScope; - private ?string $applicationToken; + private ?string $applicationToken = null; private ?string $comment; public function __construct( @@ -146,7 +146,9 @@ public function changeDomainUrl(string $newDomainUrl): void public function applicationInstalled(string $applicationToken): void { if (Bitrix24AccountStatus::new !== $this->accountStatus) { - throw new InvalidArgumentException('new account must be in status new'); + 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'); @@ -165,10 +167,15 @@ 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', + 'application token «%s» mismatch with application token «%s» for bitrix24 account %s for domain %s', $applicationToken, $this->applicationToken, $this->id->toRfc4122(), From e4e36a8ba71ae8f937ffdf9026e5fd8ddd6db519 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 6 Jul 2024 09:10:49 +0600 Subject: [PATCH 085/138] Update method in ApplicationStatusTest The test method in ApplicationStatusTest.php has been updated from checking if the application status is local to checking if it is a subscription. This change will ensure that the unit tests are accurately reflecting the application's subscription status. Signed-off-by: mesilov --- tests/Unit/Application/ApplicationStatusTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Unit/Application/ApplicationStatusTest.php b/tests/Unit/Application/ApplicationStatusTest.php index 5d1a16b3..7b314f1e 100644 --- a/tests/Unit/Application/ApplicationStatusTest.php +++ b/tests/Unit/Application/ApplicationStatusTest.php @@ -73,7 +73,7 @@ public function testLocal(): void public function testSubscription(): void { - $this->assertTrue(ApplicationStatus::subscription()->isLocal()); + $this->assertTrue(ApplicationStatus::subscription()->isSubscription()); } /** From b460b22f508f0a7d466959b7491c8f24687fc087 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 7 Jul 2024 01:45:22 +0600 Subject: [PATCH 086/138] Add sorting and equality function to Scope The commit includes the addition of a sorting step in the Scope constructor that ensures that the order of scope values is consistent. Also, a new method 'equal' has been added to compare if two scope instances are equal based on their values. Signed-off-by: mesilov --- src/Core/Credentials/Scope.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Core/Credentials/Scope.php b/src/Core/Credentials/Scope.php index dae5cbb4..b280269a 100644 --- a/src/Core/Credentials/Scope.php +++ b/src/Core/Credentials/Scope.php @@ -84,7 +84,7 @@ class Scope public function __construct(array $scope = []) { $scope = array_unique(array_map('strtolower', $scope)); - + sort($scope); if (count($scope) === 1 && $scope[0] === '') { $scope = []; } else { @@ -98,6 +98,11 @@ public function __construct(array $scope = []) $this->currentScope = $scope; } + public function equal(self $scope): bool + { + return $this->currentScope === $scope->getScopeCodes(); + } + public function getScopeCodes(): array { return $this->currentScope; From 5da2ef12c1bf1b11dd342fd4bd312e5be9eb0a2a Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 7 Jul 2024 01:45:47 +0600 Subject: [PATCH 087/138] Add new test case and refactor ScopeTest Added test case 'testEqual' to enhance the coverage of code in ScopeTest. Simplified the occurrences of UnknownScopeCodeException in all test cases, and corrected the order of scope codes inside the 'testInitFromString' test case. Signed-off-by: mesilov --- tests/Unit/Core/Credentials/ScopeTest.php | 25 +++++++++++++++-------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/tests/Unit/Core/Credentials/ScopeTest.php b/tests/Unit/Core/Credentials/ScopeTest.php index e974fd36..4933f2df 100644 --- a/tests/Unit/Core/Credentials/ScopeTest.php +++ b/tests/Unit/Core/Credentials/ScopeTest.php @@ -8,15 +8,10 @@ use Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException; use PHPUnit\Framework\TestCase; -/** - * Class ScopeTest - * - * @package Bitrix24\SDK\Tests\Unit\Core - */ class ScopeTest extends TestCase { /** - * @throws \Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException + * @throws UnknownScopeCodeException */ public function testBuildScopeFromArray(): void { @@ -73,6 +68,16 @@ public function testUnknownScope(): void $scope = 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 */ @@ -89,18 +94,20 @@ public function testWrongScopeCode(): void { $scope = new Scope(['CRM', 'Call', 'im']); - $this->assertEquals(['crm', 'call', 'im'], $scope->getScopeCodes()); + $this->assertEquals(['call', 'crm', 'im'], $scope->getScopeCodes()); } /** * @return void - * @throws \Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException + * @throws UnknownScopeCodeException * @covers \Bitrix24\SDK\Core\Credentials\Scope::initFromString * @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(['crm', 'telephony', 'call', 'user_basic', 'placement', 'im', 'imopenlines'], $scope->getScopeCodes()); + $this->assertEquals($scopeList, $scope->getScopeCodes()); } } From d04c08aeeadeb9a6b0094e783439b1c19d6a3f7d Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 7 Jul 2024 01:47:08 +0600 Subject: [PATCH 088/138] Add additional tests and improve account status change This update adds more unit tests to validate application behavior. Particularly, tests for methods like 'isApplicationTokenValid', 'getCreatedAt', and 'getUpdatedAt' have been included. Also, the account status change from 'active' to 'blocked' has been corrected. Signed-off-by: mesilov --- phpunit.xml.dist | 57 ++-- ...ntInterfaceReferenceImplementationTest.php | 3 +- .../Entity/Bitrix24AccountInterfaceTest.php | 293 +++++++++++++++++- ...24AccountReferenceEntityImplementation.php | 9 +- 4 files changed, 316 insertions(+), 46 deletions(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index e878d19c..3cdf6e26 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,31 +1,32 @@ - - - - - - ./tests/Unit - - - ./tests/Integration - - - ./tests/Integration/Core/ - - - ./tests/Integration/Services/Telephony/ - - - ./tests/Integration/Services/User/ - - - ./tests/Integration/Services/Workflows/ - - - - - ./src - - + + + + + + ./tests/Unit + ./tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php + + + ./tests/Integration + + + ./tests/Integration/Core/ + + + ./tests/Integration/Services/Telephony/ + + + ./tests/Integration/Services/User/ + + + ./tests/Integration/Services/Workflows/ + + + + + ./src + + diff --git a/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceReferenceImplementationTest.php b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceReferenceImplementationTest.php index 0d4ad60c..a1da3dc7 100644 --- a/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceReferenceImplementationTest.php +++ b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceReferenceImplementationTest.php @@ -12,9 +12,10 @@ use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; use Carbon\CarbonImmutable; use Generator; +use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; use Symfony\Component\Uid\Uuid; - +#[CoversClass(Bitrix24AccountInterface::class)] class Bitrix24AccountInterfaceReferenceImplementationTest extends Bitrix24AccountInterfaceTest { protected function createBitrix24AccountImplementation( diff --git a/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php index 61352ac8..00ad7478 100644 --- a/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php +++ b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php @@ -22,7 +22,6 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Uid\Uuid; use Throwable; - #[CoversClass(Bitrix24AccountInterface::class)] abstract class Bitrix24AccountInterfaceTest extends TestCase { @@ -288,6 +287,9 @@ final public function testChangeDomainUrl( $this->assertEquals($newDomainUrl, $ob->getDomainUrl()); } + /** + * @throws InvalidArgumentException + */ #[Test] #[DataProvider('bitrix24AccountForInstallDataProvider')] #[TestDox('test applicationInstalled method')] @@ -319,19 +321,19 @@ final public function testApplicationInstalled( #[DataProvider('bitrix24AccountForUninstallDataProvider')] #[TestDox('test applicationUninstalled method')] final public function testApplicationUninstalled( - Uuid $id, - int $bitrix24UserId, - bool $isBitrix24UserAdmin, - string $memberId, - string $domainUrl, - Bitrix24AccountStatus $accountStatusForInstall, - AuthToken $authToken, - CarbonImmutable $createdAt, - CarbonImmutable $updatedAt, - int $applicationVersion, - Scope $applicationScope, - string $applicationToken, - ?Throwable $exception + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatusForInstall, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope, + string $applicationToken, + ?Throwable $exception ): void { if ($exception !== null) { @@ -343,6 +345,266 @@ final public function testApplicationUninstalled( $this->assertEquals(Bitrix24AccountStatus::deleted, $ob->getStatus()); } + /** + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('bitrix24AccountWithStatusNewDataProvider')] + #[TestDox('test isApplicationTokenValid method')] + final public function testIsApplicationTokenValid( + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope, + string $applicationToken, + ): void + { + $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertFalse($ob->isApplicationTokenValid($applicationToken)); + $ob->applicationInstalled($applicationToken); + $this->assertTrue($ob->isApplicationTokenValid($applicationToken)); + } + + /** + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('bitrix24AccountWithStatusNewDataProvider')] + #[TestDox('test getCreatedAt method')] + final public function testGetCreatedAt( + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope, + string $applicationToken, + ): void + { + $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertTrue($ob->getCreatedAt()->equalTo($createdAt)); + $ob->applicationInstalled($applicationToken); + $this->assertTrue($ob->getCreatedAt()->equalTo($createdAt)); + } + + /** + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('bitrix24AccountWithStatusNewDataProvider')] + #[TestDox('test getUpdatedAt method')] + final public function testGetUpdatedAt( + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope, + string $applicationToken, + ): void + { + $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertTrue($ob->getUpdatedAt()->equalTo($updatedAt)); + $ob->applicationInstalled($applicationToken); + $this->assertFalse($ob->getUpdatedAt()->equalTo($createdAt)); + } + + /** + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('bitrix24AccountWithStatusNewDataProvider')] + #[TestDox('test updateApplicationVersion method')] + final public function testUpdateApplicationVersion( + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope, + string $applicationToken, + int $newApplicationVersion, + Scope $newApplicationScope, + ?Throwable $exception + ): void + { + if ($exception !== null) { + $this->expectException($exception::class); + } + $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $ob->applicationInstalled($applicationToken); + $ob->updateApplicationVersion($newApplicationVersion, $newApplicationScope); + $this->assertEquals($newApplicationVersion, $ob->getApplicationVersion()); + $this->assertTrue($newApplicationScope->equal($ob->getApplicationScope())); + } + + /** + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test markAsBlocked and getComment methods')] + final public function testMarkAsBlocked( + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope, + string $applicationToken, + ?Throwable $exception + ): void + { + if ($exception !== null) { + $this->expectException($exception::class); + } + $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $ob->applicationInstalled($applicationToken); + $comment = 'block account just for fun'; + $ob->markAsBlocked($comment); + $this->assertEquals(Bitrix24AccountStatus::blocked, $ob->getStatus()); + $this->assertEquals($comment, $ob->getComment()); + } + + /** + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test markAsActive and getComment methods')] + final public function testMarkAsActive( + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope, + string $applicationToken, + ?Throwable $exception + ): void + { + if ($exception !== null) { + $this->expectException($exception::class); + } + $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $ob->applicationInstalled($applicationToken); + $comment = 'block account just for fun'; + $ob->markAsBlocked($comment); + $this->assertEquals(Bitrix24AccountStatus::blocked, $ob->getStatus()); + $this->assertEquals($comment, $ob->getComment()); + $comment = 'activate account'; + $ob->markAsActive($comment); + $this->assertEquals(Bitrix24AccountStatus::active, $ob->getStatus()); + $this->assertEquals($comment, $ob->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' => [ @@ -424,6 +686,9 @@ public static function bitrix24AccountForUninstallDataProvider(): Generator ]; } + /** + * @throws UnknownScopeCodeException + */ public static function bitrix24AccountForInstallDataProvider(): Generator { yield 'empty-application-token' => [ diff --git a/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountReferenceEntityImplementation.php b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountReferenceEntityImplementation.php index d8b007f0..ebaf355a 100644 --- a/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountReferenceEntityImplementation.php +++ b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountReferenceEntityImplementation.php @@ -9,6 +9,7 @@ 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; @@ -18,7 +19,6 @@ * * This class uses ONLY for demonstration and tests interface, use cases for work with Bitrix24AccountInterface methods * - * @implements Bitrix24AccountInterface */ final class Bitrix24AccountReferenceEntityImplementation implements Bitrix24AccountInterface { @@ -112,6 +112,9 @@ public function getApplicationVersion(): int return $this->applicationVersion; } + /** + * @throws UnknownScopeCodeException + */ public function getApplicationScope(): Scope { return new Scope($this->applicationScope); @@ -249,7 +252,7 @@ public function markAsBlocked(?string $comment): void throw new InvalidArgumentException('you cannot block account in status «deleted»'); } - $this->accountStatus = Bitrix24AccountStatus::active; + $this->accountStatus = Bitrix24AccountStatus::blocked; $this->comment = $comment; $this->updatedAt = new CarbonImmutable(); } @@ -258,4 +261,4 @@ public function getComment(): ?string { return $this->comment; } -} \ No newline at end of file +} From 2afc7d6025fdc18a043cf7dc34c330b30a8fb76b Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 7 Jul 2024 02:26:00 +0600 Subject: [PATCH 089/138] Refactor tests and classes to use PHP attributes This commit updates all test cases to use native PHP8 attribute syntax instead of comments for PHPUnit annotations. The method visibility has also been adjusted to be compliant with the PHPUnit v9. Additionally, multiple unnecessary comment blocks have been removed from the source codes for better readability. All changes have been made across various classes and test cases. Signed-off-by: mesilov --- phpstan.neon.dist | 4 +- rector.php | 2 + src/Application/ApplicationStatus.php | 37 +---- .../Entity/Bitrix24AccountInterface.php | 6 +- .../Bitrix24AccountRepositoryInterface.php | 5 +- src/Application/Requests/AbstractRequest.php | 11 +- .../Requests/Events/AbstractEventRequest.php | 6 +- .../Requests/Placement/PlacementRequest.php | 50 +++--- .../Application/ApplicationStatusTest.php | 14 +- ...ntInterfaceReferenceImplementationTest.php | 8 +- .../Entity/Bitrix24AccountInterfaceTest.php | 149 +++++++++--------- ...24AccountReferenceEntityImplementation.php | 34 ++-- tests/Unit/Core/ApiLevelErrorHandlerTest.php | 7 +- tests/Unit/Core/CoreBuilderTest.php | 4 +- .../Credentials/ApplicationProfileTest.php | 12 +- .../Unit/Core/Credentials/CredentialsTest.php | 6 +- tests/Unit/Core/Credentials/ScopeTest.php | 7 +- .../Unit/Core/Credentials/WebhookUrlTest.php | 17 +- tests/Unit/Core/Response/DTO/TimeTest.php | 5 +- tests/Unit/Core/Result/AbstractItemTest.php | 29 ++-- .../DefaultRequestIdGeneratorTest.php | 11 +- .../Services/CRM/CRMServiceBuilderTest.php | 24 +-- .../Unit/Services/IM/IMServiceBuilderTest.php | 6 +- .../Services/Main/MainServiceBuilderTest.php | 6 +- tests/Unit/Services/ServiceBuilderTest.php | 12 +- tests/Unit/Stubs/NullBatch.php | 20 +-- tests/Unit/Stubs/NullCore.php | 3 - 27 files changed, 199 insertions(+), 296 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 6a8ea16d..c46a4832 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -4,6 +4,7 @@ parameters: - src/ - tests/Integration/Services/Telephony - tests/Integration/Services/User + - tests/Unit/ bootstrapFiles: - tests/bootstrap.php parallel: @@ -11,4 +12,5 @@ parameters: maximumNumberOfProcesses: 8 minimumNumberOfJobsPerProcess: 2 editorUrlTitle: '%%relFile%%:%%line%%' - editorUrl: 'phpstorm://open?file=%%file%%&line=%%line%%' \ No newline at end of file + editorUrl: 'phpstorm://open?file=%%file%%&line=%%line%%' + treatPhpDocTypesAsCertain: false diff --git a/rector.php b/rector.php index 87d3e575..15a6dad1 100644 --- a/rector.php +++ b/rector.php @@ -10,10 +10,12 @@ return RectorConfig::configure() ->withPaths([ __DIR__ . '/src/Core/', + __DIR__ . '/src/Application/', __DIR__ . '/src/Services/Telephony', __DIR__ . '/tests/Integration/Services/Telephony', __DIR__ . '/src/Services/User', __DIR__ . '/tests/Integration/Services/User', + __DIR__ . '/tests/Unit/', ]) ->withCache(cacheDirectory: __DIR__ . '.cache/rector') ->withSets( diff --git a/src/Application/ApplicationStatus.php b/src/Application/ApplicationStatus.php index 65352c03..a6cc86a1 100644 --- a/src/Application/ApplicationStatus.php +++ b/src/Application/ApplicationStatus.php @@ -10,16 +10,20 @@ 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 string $statusCode; + + private readonly string $statusCode; /** - * @param string $statusShortCode - * * @throws InvalidArgumentException */ public function __construct(string $statusShortCode) @@ -42,17 +46,11 @@ public static function free(): self return new self(self::STATUS_SHORT_FREE); } - /** - * @return bool - */ public function isFree(): bool { return 'free' === $this->statusCode; } - /** - * @return bool - */ public function isDemo(): bool { return 'demo' === $this->statusCode; @@ -63,9 +61,6 @@ public static function demo(): self return new self(self::STATUS_SHORT_DEMO); } - /** - * @return bool - */ public function isTrial(): bool { return 'trial' === $this->statusCode; @@ -76,9 +71,6 @@ public static function trial(): self return new self(self::STATUS_SHORT_TRIAL); } - /** - * @return bool - */ public function isPaid(): bool { return 'paid' === $this->statusCode; @@ -89,9 +81,6 @@ public static function paid(): self return new self(self::STATUS_SHORT_PAID); } - /** - * @return bool - */ public function isLocal(): bool { return 'local' === $this->statusCode; @@ -102,9 +91,6 @@ public static function local(): self return new self(self::STATUS_SHORT_LOCAL); } - /** - * @return bool - */ public function isSubscription(): bool { return 'subscription' === $this->statusCode; @@ -115,18 +101,12 @@ public static function subscription(): self return new self(self::STATUS_SHORT_SUBSCRIPTION); } - /** - * @return string - */ public function getStatusCode(): string { return $this->statusCode; } /** - * @param Request $request - * - * @return self * @throws InvalidArgumentException */ public static function initFromRequest(Request $request): self @@ -135,9 +115,6 @@ public static function initFromRequest(Request $request): self } /** - * @param string $shortStatusCode - * - * @return self * @throws InvalidArgumentException */ public static function initFromString(string $shortStatusCode): self diff --git a/src/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterface.php b/src/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterface.php index 2c13a192..cf6a9b4e 100644 --- a/src/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterface.php +++ b/src/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterface.php @@ -48,11 +48,7 @@ public function getStatus(): Bitrix24AccountStatus; */ public function getAuthToken(): AuthToken; - /** - * @param RenewedAuthToken $renewedAuthToken - * - * @return void - */ + public function renewAuthToken(RenewedAuthToken $renewedAuthToken): void; /** diff --git a/src/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterface.php b/src/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterface.php index 68b73f66..4d2a6361 100644 --- a/src/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterface.php +++ b/src/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterface.php @@ -12,11 +12,10 @@ interface Bitrix24AccountRepositoryInterface /** * Get Bitrix24 account by id */ - public function getById(Uuid $id): Bitrix24Accounts\Entity\Bitrix24AccountInterface; + public function getById(Uuid $uuid): Bitrix24Accounts\Entity\Bitrix24AccountInterface; /** - * @param Bitrix24Accounts\Entity\Bitrix24AccountInterface $entity * @param bool $isFlush save entity to storage, commit transaction in oltp database */ - public function save(Bitrix24Accounts\Entity\Bitrix24AccountInterface $entity, bool $isFlush = false): void; + public function save(Bitrix24Accounts\Entity\Bitrix24AccountInterface $bitrix24Account, bool $isFlush = false): void; } \ No newline at end of file diff --git a/src/Application/Requests/AbstractRequest.php b/src/Application/Requests/AbstractRequest.php index be080268..1adcb543 100644 --- a/src/Application/Requests/AbstractRequest.php +++ b/src/Application/Requests/AbstractRequest.php @@ -8,19 +8,10 @@ abstract class AbstractRequest { - protected Request $request; - - /** - * @param \Symfony\Component\HttpFoundation\Request $request - */ - public function __construct(Request $request) + public function __construct(protected Request $request) { - $this->request = $request; } - /** - * @return \Symfony\Component\HttpFoundation\Request - */ public function getRequest(): Request { return $this->request; diff --git a/src/Application/Requests/Events/AbstractEventRequest.php b/src/Application/Requests/Events/AbstractEventRequest.php index 750e5a8e..ba207e3b 100644 --- a/src/Application/Requests/Events/AbstractEventRequest.php +++ b/src/Application/Requests/Events/AbstractEventRequest.php @@ -10,13 +10,13 @@ abstract class AbstractEventRequest extends AbstractRequest implements EventInterface { protected string $eventCode; + protected int $timestamp; + protected array $eventPayload; + protected int $eventId; - /** - * @param Request $request - */ public function __construct(Request $request) { parent::__construct($request); diff --git a/src/Application/Requests/Placement/PlacementRequest.php b/src/Application/Requests/Placement/PlacementRequest.php index 27d0c9ec..9873ed46 100644 --- a/src/Application/Requests/Placement/PlacementRequest.php +++ b/src/Application/Requests/Placement/PlacementRequest.php @@ -12,19 +12,24 @@ class PlacementRequest extends AbstractRequest { - private AuthToken $accessToken; - private string $memberId; - private ApplicationStatus $applicationStatus; - private string $code; + private readonly AuthToken $accessToken; + + private readonly string $memberId; + + private readonly ApplicationStatus $applicationStatus; + + private readonly string $code; + /** * @var array */ - private array $placementOptions; - private string $domainUrl; - private string $languageCode; + private readonly array $placementOptions; + + private readonly string $domainUrl; + + private readonly string $languageCode; /** - * @param \Symfony\Component\HttpFoundation\Request $request * * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException * @throws \JsonException @@ -47,10 +52,12 @@ public function __construct(Request $request) 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; } @@ -59,50 +66,35 @@ public function getApplicationStatus(): ApplicationStatus return $this->applicationStatus; } - /** - * @return string - */ public function getMemberId(): string { return $this->memberId; } - /** - * @return \Bitrix24\SDK\Core\Credentials\AuthToken - */ public function getAccessToken(): AuthToken { return $this->accessToken; } - /** - * @return string - */ public function getCode(): string { return $this->code; } - /** - * @return array|mixed - */ - public function getPlacementOptions() + + public function getPlacementOptions(): array { return $this->placementOptions; } - /** - * @return mixed|string - */ - public function getDomainUrl() + + public function getDomainUrl(): string { return $this->domainUrl; } - /** - * @return mixed|string - */ - public function getLanguageCode() + + public function getLanguageCode(): string { return $this->languageCode; } diff --git a/tests/Unit/Application/ApplicationStatusTest.php b/tests/Unit/Application/ApplicationStatusTest.php index 7b314f1e..857f7f00 100644 --- a/tests/Unit/Application/ApplicationStatusTest.php +++ b/tests/Unit/Application/ApplicationStatusTest.php @@ -9,16 +9,14 @@ use Generator; use PHPUnit\Framework\TestCase; +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Application\ApplicationStatus::class)] class ApplicationStatusTest extends TestCase { /** - * @param string $shortCode - * @param string $longCode * - * @return void - * @dataProvider statusDataProvider * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException */ + #[\PHPUnit\Framework\Attributes\DataProvider('statusDataProvider')] public function testGetStatusCode(string $shortCode, string $longCode): void { $this->assertEquals( @@ -27,9 +25,6 @@ public function testGetStatusCode(string $shortCode, string $longCode): void ); } - /** - * @return void - */ public function testInvalidStatusCode(): void { $this->expectException(InvalidArgumentException::class); @@ -37,9 +32,7 @@ public function testInvalidStatusCode(): void } /** - * @return void * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException - * @covers \Bitrix24\SDK\Application\ApplicationStatus::initFromString */ public function testInitFromString(): void { @@ -76,9 +69,6 @@ public function testSubscription(): void $this->assertTrue(ApplicationStatus::subscription()->isSubscription()); } - /** - * @return \Generator - */ public static function statusDataProvider(): Generator { yield 'free' => [ diff --git a/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceReferenceImplementationTest.php b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceReferenceImplementationTest.php index a1da3dc7..7b5f748a 100644 --- a/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceReferenceImplementationTest.php +++ b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceReferenceImplementationTest.php @@ -19,12 +19,12 @@ class Bitrix24AccountInterfaceReferenceImplementationTest extends Bitrix24AccountInterfaceTest { protected function createBitrix24AccountImplementation( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -33,12 +33,12 @@ protected function createBitrix24AccountImplementation( ): Bitrix24AccountInterface { return new Bitrix24AccountReferenceEntityImplementation( - $id, + $uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, - $accountStatus, + $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, diff --git a/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php index 00ad7478..03b4e5c2 100644 --- a/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php +++ b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php @@ -26,12 +26,12 @@ abstract class Bitrix24AccountInterfaceTest extends TestCase { abstract protected function createBitrix24AccountImplementation( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -56,8 +56,8 @@ final public function testGetId( Scope $applicationScope ): void { - $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $this->assertEquals($id, $ob->getId()); + $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertEquals($id, $bitrix24Account->getId()); } #[Test] @@ -77,8 +77,8 @@ final public function testGetBitrix24UserId( Scope $applicationScope ): void { - $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $this->assertEquals($bitrix24UserId, $ob->getBitrix24UserId()); + $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertEquals($bitrix24UserId, $bitrix24Account->getBitrix24UserId()); } #[Test] @@ -98,8 +98,8 @@ final public function testisBitrix24UserAdmin( Scope $applicationScope ): void { - $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $this->assertEquals($isBitrix24UserAdmin, $ob->isBitrix24UserAdmin()); + $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertEquals($isBitrix24UserAdmin, $bitrix24Account->isBitrix24UserAdmin()); } #[Test] @@ -119,8 +119,8 @@ final public function testGetMemberId( Scope $applicationScope ): void { - $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $this->assertEquals($memberId, $ob->getMemberId()); + $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertEquals($memberId, $bitrix24Account->getMemberId()); } #[Test] @@ -140,8 +140,8 @@ final public function testGetDomainUrl( Scope $applicationScope ): void { - $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $this->assertEquals($domainUrl, $ob->getDomainUrl()); + $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertEquals($domainUrl, $bitrix24Account->getDomainUrl()); } #[Test] @@ -161,8 +161,8 @@ final public function testGetStatus( Scope $applicationScope ): void { - $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $this->assertEquals($accountStatus, $ob->getStatus()); + $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertEquals($accountStatus, $bitrix24Account->getStatus()); } #[Test] @@ -182,8 +182,8 @@ final public function testGetAuthToken( Scope $applicationScope ): void { - $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $this->assertEquals($authToken, $ob->getAuthToken()); + $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertEquals($authToken, $bitrix24Account->getAuthToken()); } #[Test] @@ -203,7 +203,7 @@ final public function testRenewAuthToken( Scope $applicationScope ): void { - $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); $newAuthToken = new AuthToken('access_token-2', 'refresh_token=2', 1609459202); $appStatus = ApplicationStatus::subscription(); @@ -215,10 +215,10 @@ final public function testRenewAuthToken( $appStatus, $domainUrl ); - $ob->renewAuthToken($renewedAuthToken); + $bitrix24Account->renewAuthToken($renewedAuthToken); - $this->assertEquals($newAuthToken, $ob->getAuthToken()); + $this->assertEquals($newAuthToken, $bitrix24Account->getAuthToken()); } #[Test] @@ -238,8 +238,8 @@ final public function testGetApplicationVersion( Scope $applicationScope ): void { - $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $this->assertEquals($applicationVersion, $ob->getApplicationVersion()); + $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertEquals($applicationVersion, $bitrix24Account->getApplicationVersion()); } @@ -260,8 +260,8 @@ final public function testGetApplicationScope( Scope $applicationScope ): void { - $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $this->assertEquals($applicationScope, $ob->getApplicationScope()); + $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertEquals($applicationScope, $bitrix24Account->getApplicationScope()); } #[Test] @@ -306,15 +306,16 @@ final public function testApplicationInstalled( int $applicationVersion, Scope $applicationScope, string $applicationToken, - ?Throwable $exception + ?Throwable $throwable ): void { - if ($exception !== null) { - $this->expectException($exception::class); + if ($throwable instanceof \Throwable) { + $this->expectException($throwable::class); } - $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $ob->applicationInstalled($applicationToken); - $this->assertTrue($ob->isApplicationTokenValid($applicationToken)); + + $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24Account->applicationInstalled($applicationToken); + $this->assertTrue($bitrix24Account->isApplicationTokenValid($applicationToken)); } #[Test] @@ -326,7 +327,7 @@ final public function testApplicationUninstalled( bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatusForInstall, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -336,13 +337,14 @@ final public function testApplicationUninstalled( ?Throwable $exception ): void { - if ($exception !== null) { + if ($exception instanceof \Throwable) { $this->expectException($exception::class); } - $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatusForInstall, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $ob->applicationInstalled($applicationToken); - $ob->applicationUninstalled($applicationToken); - $this->assertEquals(Bitrix24AccountStatus::deleted, $ob->getStatus()); + + $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24Account->applicationInstalled($applicationToken); + $bitrix24Account->applicationUninstalled($applicationToken); + $this->assertEquals(Bitrix24AccountStatus::deleted, $bitrix24Account->getStatus()); } /** @@ -357,7 +359,7 @@ final public function testIsApplicationTokenValid( bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -366,10 +368,10 @@ final public function testIsApplicationTokenValid( string $applicationToken, ): void { - $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $this->assertFalse($ob->isApplicationTokenValid($applicationToken)); - $ob->applicationInstalled($applicationToken); - $this->assertTrue($ob->isApplicationTokenValid($applicationToken)); + $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertFalse($bitrix24Account->isApplicationTokenValid($applicationToken)); + $bitrix24Account->applicationInstalled($applicationToken); + $this->assertTrue($bitrix24Account->isApplicationTokenValid($applicationToken)); } /** @@ -393,10 +395,10 @@ final public function testGetCreatedAt( string $applicationToken, ): void { - $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $this->assertTrue($ob->getCreatedAt()->equalTo($createdAt)); - $ob->applicationInstalled($applicationToken); - $this->assertTrue($ob->getCreatedAt()->equalTo($createdAt)); + $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertTrue($bitrix24Account->getCreatedAt()->equalTo($createdAt)); + $bitrix24Account->applicationInstalled($applicationToken); + $this->assertTrue($bitrix24Account->getCreatedAt()->equalTo($createdAt)); } /** @@ -420,10 +422,10 @@ final public function testGetUpdatedAt( string $applicationToken, ): void { - $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $this->assertTrue($ob->getUpdatedAt()->equalTo($updatedAt)); - $ob->applicationInstalled($applicationToken); - $this->assertFalse($ob->getUpdatedAt()->equalTo($createdAt)); + $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $this->assertTrue($bitrix24Account->getUpdatedAt()->equalTo($updatedAt)); + $bitrix24Account->applicationInstalled($applicationToken); + $this->assertFalse($bitrix24Account->getUpdatedAt()->equalTo($createdAt)); } /** @@ -447,17 +449,18 @@ final public function testUpdateApplicationVersion( string $applicationToken, int $newApplicationVersion, Scope $newApplicationScope, - ?Throwable $exception + ?Throwable $throwable ): void { - if ($exception !== null) { - $this->expectException($exception::class); + if ($throwable instanceof \Throwable) { + $this->expectException($throwable::class); } - $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $ob->applicationInstalled($applicationToken); - $ob->updateApplicationVersion($newApplicationVersion, $newApplicationScope); - $this->assertEquals($newApplicationVersion, $ob->getApplicationVersion()); - $this->assertTrue($newApplicationScope->equal($ob->getApplicationScope())); + + $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24Account->applicationInstalled($applicationToken); + $bitrix24Account->updateApplicationVersion($newApplicationVersion, $newApplicationScope); + $this->assertEquals($newApplicationVersion, $bitrix24Account->getApplicationVersion()); + $this->assertTrue($newApplicationScope->equal($bitrix24Account->getApplicationScope())); } /** @@ -482,15 +485,17 @@ final public function testMarkAsBlocked( ?Throwable $exception ): void { - if ($exception !== null) { + if ($exception instanceof \Throwable) { $this->expectException($exception::class); } - $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $ob->applicationInstalled($applicationToken); + + $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24Account->applicationInstalled($applicationToken); + $comment = 'block account just for fun'; - $ob->markAsBlocked($comment); - $this->assertEquals(Bitrix24AccountStatus::blocked, $ob->getStatus()); - $this->assertEquals($comment, $ob->getComment()); + $bitrix24Account->markAsBlocked($comment); + $this->assertEquals(Bitrix24AccountStatus::blocked, $bitrix24Account->getStatus()); + $this->assertEquals($comment, $bitrix24Account->getComment()); } /** @@ -515,19 +520,21 @@ final public function testMarkAsActive( ?Throwable $exception ): void { - if ($exception !== null) { + if ($exception instanceof \Throwable) { $this->expectException($exception::class); } - $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $ob->applicationInstalled($applicationToken); + + $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24Account->applicationInstalled($applicationToken); + $comment = 'block account just for fun'; - $ob->markAsBlocked($comment); - $this->assertEquals(Bitrix24AccountStatus::blocked, $ob->getStatus()); - $this->assertEquals($comment, $ob->getComment()); + $bitrix24Account->markAsBlocked($comment); + $this->assertEquals(Bitrix24AccountStatus::blocked, $bitrix24Account->getStatus()); + $this->assertEquals($comment, $bitrix24Account->getComment()); $comment = 'activate account'; - $ob->markAsActive($comment); - $this->assertEquals(Bitrix24AccountStatus::active, $ob->getStatus()); - $this->assertEquals($comment, $ob->getComment()); + $bitrix24Account->markAsActive($comment); + $this->assertEquals(Bitrix24AccountStatus::active, $bitrix24Account->getStatus()); + $this->assertEquals($comment, $bitrix24Account->getComment()); } /** diff --git a/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountReferenceEntityImplementation.php b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountReferenceEntityImplementation.php index ebaf355a..ce763563 100644 --- a/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountReferenceEntityImplementation.php +++ b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountReferenceEntityImplementation.php @@ -23,21 +23,26 @@ final class Bitrix24AccountReferenceEntityImplementation implements Bitrix24AccountInterface { private string $accessToken; + private string $refreshToken; + private int $expires; + private array $applicationScope; + private ?string $applicationToken = null; - private ?string $comment; + + private ?string $comment = null; public function __construct( - private Uuid $id, - private int $bitrix24UserId, - private bool $isBitrix24UserAdmin, - private string $memberId, + 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 CarbonImmutable $createdAt, + private readonly CarbonImmutable $createdAt, private CarbonImmutable $updatedAt, private int $applicationVersion, Scope $applicationScope, @@ -89,13 +94,13 @@ public function getAuthToken(): AuthToken */ public function renewAuthToken(RenewedAuthToken $renewedAuthToken): void { - if ($this->getMemberId() !== $renewedAuthToken->memberId) { + 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->getMemberId(), - $this->getId()->toRfc4122(), - $this->getDomainUrl(), + $this->memberId, + $this->id->toRfc4122(), + $this->domainUrl, $renewedAuthToken->memberId, ) ); @@ -128,6 +133,7 @@ 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( @@ -153,6 +159,7 @@ public function applicationInstalled(string $applicationToken): void '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'); } @@ -170,11 +177,13 @@ 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( @@ -214,16 +223,19 @@ 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 !== null) { + if ($newScope instanceof \Bitrix24\SDK\Core\Credentials\Scope) { $this->applicationScope = $newScope->getScopeCodes(); } + $this->updatedAt = new CarbonImmutable(); } diff --git a/tests/Unit/Core/ApiLevelErrorHandlerTest.php b/tests/Unit/Core/ApiLevelErrorHandlerTest.php index f8a96fee..b49b8ba4 100644 --- a/tests/Unit/Core/ApiLevelErrorHandlerTest.php +++ b/tests/Unit/Core/ApiLevelErrorHandlerTest.php @@ -14,17 +14,16 @@ use PHPUnit\Framework\TestCase; use Psr\Log\NullLogger; +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Core\ApiLevelErrorHandler::class)] class ApiLevelErrorHandlerTest extends TestCase { private ApiLevelErrorHandler $apiLevelErrorHandler; /** - * @return void * @throws \Bitrix24\SDK\Core\Exceptions\BaseException * @throws \Bitrix24\SDK\Core\Exceptions\QueryLimitExceededException - * @covers \Bitrix24\SDK\Core\ApiLevelErrorHandler::handle - * @testdox Test operating error in bach mode */ + #[\PHPUnit\Framework\Attributes\TestDox('Test operating error in bach mode')] public function testOperatingErrorInBachMode(): void { $this->expectException(OperationTimeLimitExceededException::class); @@ -44,7 +43,7 @@ public function testOperatingErrorInBachMode(): void $this->apiLevelErrorHandler->handle($response); } - public function setUp(): void + protected function setUp(): void { $this->apiLevelErrorHandler = new ApiLevelErrorHandler(new NullLogger()); } diff --git a/tests/Unit/Core/CoreBuilderTest.php b/tests/Unit/Core/CoreBuilderTest.php index 33ffa331..19ba5b02 100644 --- a/tests/Unit/Core/CoreBuilderTest.php +++ b/tests/Unit/Core/CoreBuilderTest.php @@ -19,7 +19,7 @@ class CoreBuilderTest extends TestCase */ public function testBuildWithCredentialsFromWebhook(): void { - $core = (new CoreBuilder()) + (new CoreBuilder()) ->withCredentials(Credentials::createFromWebhook(new WebhookUrl('https://127.0.0.1'))) ->build(); // successful build core @@ -33,7 +33,7 @@ public function testBuildWithCredentialsFromWebhook(): void public function testBuildWithoutCredentials(): void { $this->expectException(InvalidArgumentException::class); - $core = (new CoreBuilder()) + (new CoreBuilder()) ->build(); } } diff --git a/tests/Unit/Core/Credentials/ApplicationProfileTest.php b/tests/Unit/Core/Credentials/ApplicationProfileTest.php index 27d415f7..637c3588 100644 --- a/tests/Unit/Core/Credentials/ApplicationProfileTest.php +++ b/tests/Unit/Core/Credentials/ApplicationProfileTest.php @@ -13,22 +13,20 @@ class ApplicationProfileTest extends TestCase { /** * - * @param array $arr - * @param string|null $expectedException * - * @return void * @throws InvalidArgumentException - * @dataProvider arrayDataProvider */ + #[\PHPUnit\Framework\Attributes\DataProvider('arrayDataProvider')] public function testFromArray(array $arr, ?string $expectedException): void { if ($expectedException !== null) { $this->expectException($expectedException); } - $prof = ApplicationProfile::initFromArray($arr); - $this->assertEquals($prof->getClientId(), $arr['BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID']); - $this->assertEquals($prof->getClientSecret(), $arr['BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET']); + $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 diff --git a/tests/Unit/Core/Credentials/CredentialsTest.php b/tests/Unit/Core/Credentials/CredentialsTest.php index 827f732f..c81a7de0 100644 --- a/tests/Unit/Core/Credentials/CredentialsTest.php +++ b/tests/Unit/Core/Credentials/CredentialsTest.php @@ -25,13 +25,12 @@ class CredentialsTest extends TestCase #[DataProvider('credentialsDataProviderWithDomainUrlVariants')] public function testGetDomainUrl( Credentials $credentials, - $expectedDomainUrl + string $expectedDomainUrl ): void { $this->assertEquals($expectedDomainUrl, $credentials->getDomainUrl()); } /** - * @return void * @throws InvalidArgumentException * @throws UnknownScopeCodeException */ @@ -49,6 +48,7 @@ public function testDomainUrlWithoutProtocol(): void $credentials->getDomainUrl() ); } + #[Test] #[TestDox('tests isWebhookContext')] public function testIsWebhookContext():void @@ -62,7 +62,6 @@ public function testIsWebhookContext():void } /** - * @return void * @throws InvalidArgumentException * @throws UnknownScopeCodeException */ @@ -82,7 +81,6 @@ public function testDomainUrlWithProtocol(): void } /** - * @return Generator * @throws InvalidArgumentException * @throws UnknownScopeCodeException */ diff --git a/tests/Unit/Core/Credentials/ScopeTest.php b/tests/Unit/Core/Credentials/ScopeTest.php index 4933f2df..ab789cea 100644 --- a/tests/Unit/Core/Credentials/ScopeTest.php +++ b/tests/Unit/Core/Credentials/ScopeTest.php @@ -8,6 +8,7 @@ use Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException; use PHPUnit\Framework\TestCase; +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Core\Credentials\Scope::class)] class ScopeTest extends TestCase { /** @@ -65,7 +66,7 @@ public function testUnknownScope(): void { $this->expectException(UnknownScopeCodeException::class); - $scope = new Scope(['fooo']); + new Scope(['fooo']); } /** @@ -98,11 +99,9 @@ public function testWrongScopeCode(): void } /** - * @return void * @throws UnknownScopeCodeException - * @covers \Bitrix24\SDK\Core\Credentials\Scope::initFromString - * @testdox Test init Scope from string */ + #[\PHPUnit\Framework\Attributes\TestDox('Test init Scope from string')] public function testInitFromString(): void { $scopeList = ['crm', 'telephony', 'call', 'user_basic', 'placement', 'im', 'imopenlines']; diff --git a/tests/Unit/Core/Credentials/WebhookUrlTest.php b/tests/Unit/Core/Credentials/WebhookUrlTest.php index bc9f439b..318abec6 100644 --- a/tests/Unit/Core/Credentials/WebhookUrlTest.php +++ b/tests/Unit/Core/Credentials/WebhookUrlTest.php @@ -13,27 +13,20 @@ * * @package Bitrix24\SDK\Tests\Unit\Core */ +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Core\Credentials\WebhookUrl::class)] class WebhookUrlTest extends TestCase { - /** - * @return void - * @covers \Bitrix24\SDK\Core\Credentials\WebhookUrl - * @testdox Test valid webhook url - */ + #[\PHPUnit\Framework\Attributes\TestDox('Test valid webhook url')] public function testValidWebhookUrl(): void { - $wh = new WebhookUrl('https://bitrix24.ru/'); + new WebhookUrl('https://bitrix24.ru/'); $this->assertTrue(true); } - /** - * @return void - * @testdox Test invalid webhook url - * @covers \Bitrix24\SDK\Core\Credentials\WebhookUrl - */ + #[\PHPUnit\Framework\Attributes\TestDox('Test invalid webhook url')] public function testInvalidWebhookUrl(): void { $this->expectException(InvalidArgumentException::class); - $wh = new WebhookUrl('qqqq'); + new WebhookUrl('qqqq'); } } diff --git a/tests/Unit/Core/Response/DTO/TimeTest.php b/tests/Unit/Core/Response/DTO/TimeTest.php index 99a7db9d..34a4585b 100644 --- a/tests/Unit/Core/Response/DTO/TimeTest.php +++ b/tests/Unit/Core/Response/DTO/TimeTest.php @@ -17,8 +17,8 @@ class TimeTest extends TestCase { /** * @throws \Exception - * @dataProvider timingsDataProvider */ + #[\PHPUnit\Framework\Attributes\DataProvider('timingsDataProvider')] public function testInitFromResponseData(array $result): void { $time = Time::initFromResponse($result); @@ -33,9 +33,6 @@ public function testInitFromResponseData(array $result): void $this->assertEquals($result['date_finish'], $time->getDateFinish()->format(\DATE_ATOM)); } - /** - * @return \Generator - */ public static function timingsDataProvider(): Generator { yield 'without operating reset at' => [ diff --git a/tests/Unit/Core/Result/AbstractItemTest.php b/tests/Unit/Core/Result/AbstractItemTest.php index ce021874..6d9608de 100644 --- a/tests/Unit/Core/Result/AbstractItemTest.php +++ b/tests/Unit/Core/Result/AbstractItemTest.php @@ -8,32 +8,27 @@ use Bitrix24\SDK\Core\Result\AbstractItem; use PHPUnit\Framework\TestCase; -/** - * Class AbstractItemTest - * - * @package Bitrix24\SDK\Tests\Unit\Core\Result - */ +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Core\Result\AbstractItem::class)] class AbstractItemTest extends TestCase { - /** - * @covers \Bitrix24\SDK\Core\Result\AbstractItem::__set - */ public function testSetPropertyItem(): void { $this->expectException(ImmutableResultViolationException::class); - $testItem = new class (['ID' => 1]) extends AbstractItem { - }; - $testItem->ID = 2; + $testClassForAbstractItem = new TestClassForAbstractItem(['ID'=>1]); + $testClassForAbstractItem->ID = 2; } - /** - * @covers \Bitrix24\SDK\Core\Result\AbstractItem::__unset - */ public function testUnsetPropertyItem(): void { $this->expectException(ImmutableResultViolationException::class); - $testItem = new class (['ID' => 1]) extends AbstractItem { - }; - unset($testItem->ID); + $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 index 48b21e52..8da0bb9d 100644 --- a/tests/Unit/Infrastructure/HttpClient/RequestId/DefaultRequestIdGeneratorTest.php +++ b/tests/Unit/Infrastructure/HttpClient/RequestId/DefaultRequestIdGeneratorTest.php @@ -9,20 +9,19 @@ 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 - * @return void - * @dataProvider requestIdKeyDataProvider - * @covers \Bitrix24\SDK\Infrastructure\HttpClient\RequestId\DefaultRequestIdGenerator::getRequestId */ - public function testExistsRequestId($requestIdKey, $requestId): void + #[\PHPUnit\Framework\Attributes\DataProvider('requestIdKeyDataProvider')] + public function testExistsRequestId(string $requestIdKey, string $requestId): void { $_SERVER[$requestIdKey] = $requestId; - $gen = new DefaultRequestIdGenerator(); - $this->assertEquals($requestId, $gen->getRequestId()); + $defaultRequestIdGenerator = new DefaultRequestIdGenerator(); + $this->assertEquals($requestId, $defaultRequestIdGenerator->getRequestId()); unset($_SERVER[$requestIdKey]); } diff --git a/tests/Unit/Services/CRM/CRMServiceBuilderTest.php b/tests/Unit/Services/CRM/CRMServiceBuilderTest.php index d72586c3..91a29bca 100644 --- a/tests/Unit/Services/CRM/CRMServiceBuilderTest.php +++ b/tests/Unit/Services/CRM/CRMServiceBuilderTest.php @@ -17,74 +17,54 @@ * * @package Bitrix24\SDK\Tests\Unit\Services\CRM */ +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\CRM\CRMServiceBuilder::class)] class CRMServiceBuilderTest extends TestCase { private CRMServiceBuilder $serviceBuilder; - /** - * @covers \Bitrix24\SDK\Services\CRM\CRMServiceBuilder::settings - */ public function testGetSettingsService(): void { $this->serviceBuilder->settings(); $this::assertTrue(true); } - /** - * @covers \Bitrix24\SDK\Services\CRM\CRMServiceBuilder::dealContact - */ public function testGetDealContactService(): void { $this->serviceBuilder->dealContact(); $this::assertTrue(true); } - /** - * @covers \Bitrix24\SDK\Services\CRM\CRMServiceBuilder::dealCategory - */ public function testGetDealCategoryService(): void { $this->serviceBuilder->dealCategory(); $this::assertTrue(true); } - /** - * @covers \Bitrix24\SDK\Services\CRM\CRMServiceBuilder::dealCategory - */ public function testDealService(): void { $this->serviceBuilder->deal(); $this::assertTrue(true); } - /** - * @covers \Bitrix24\SDK\Services\CRM\CRMServiceBuilder::contact - */ public function testContactService(): void { $this->serviceBuilder->contact(); $this::assertTrue(true); } - /** - * @covers \Bitrix24\SDK\Services\CRM\CRMServiceBuilder::dealProductRows - */ public function testDealProductRowsService(): void { $this->serviceBuilder->dealProductRows(); $this::assertTrue(true); } - /** - * @covers \Bitrix24\SDK\Services\CRM\CRMServiceBuilder::dealCategoryStage - */ public function testDealCategoryStageService(): void { $this->serviceBuilder->dealCategoryStage(); $this::assertTrue(true); } - public function setUp(): void + protected function setUp(): void { $this->serviceBuilder = (new ServiceBuilder( new NullCore(), diff --git a/tests/Unit/Services/IM/IMServiceBuilderTest.php b/tests/Unit/Services/IM/IMServiceBuilderTest.php index 21b7d228..27b5bc8a 100644 --- a/tests/Unit/Services/IM/IMServiceBuilderTest.php +++ b/tests/Unit/Services/IM/IMServiceBuilderTest.php @@ -17,20 +17,18 @@ * * @package Bitrix24\SDK\Tests\Unit\Services\IM */ +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\IM\IMServiceBuilder::class)] class IMServiceBuilderTest extends TestCase { private IMServiceBuilder $serviceBuilder; - /** - * @covers \Bitrix24\SDK\Services\IM\IMServiceBuilder::IM - */ public function testGetIMService(): void { $this->serviceBuilder->IM(); $this::assertTrue(true); } - public function setUp(): void + protected function setUp(): void { $this->serviceBuilder = ( new ServiceBuilder( diff --git a/tests/Unit/Services/Main/MainServiceBuilderTest.php b/tests/Unit/Services/Main/MainServiceBuilderTest.php index c90df171..255207b5 100644 --- a/tests/Unit/Services/Main/MainServiceBuilderTest.php +++ b/tests/Unit/Services/Main/MainServiceBuilderTest.php @@ -17,20 +17,18 @@ * * @package Bitrix24\SDK\Tests\Unit\Services\CRM */ +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\Main\MainServiceBuilder::class)] class MainServiceBuilderTest extends TestCase { private MainServiceBuilder $serviceBuilder; - /** - * @covers \Bitrix24\SDK\Services\Main\MainServiceBuilder::main - */ public function testGetMainService(): void { $this->serviceBuilder->main(); $this::assertTrue(true); } - public function setUp(): void + protected function setUp(): void { $this->serviceBuilder = (new ServiceBuilder( new NullCore(), diff --git a/tests/Unit/Services/ServiceBuilderTest.php b/tests/Unit/Services/ServiceBuilderTest.php index 9a8abe94..f50cfb00 100644 --- a/tests/Unit/Services/ServiceBuilderTest.php +++ b/tests/Unit/Services/ServiceBuilderTest.php @@ -16,38 +16,30 @@ * * @package Bitrix24\SDK\Tests\Unit\Services */ +#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\ServiceBuilder::class)] class ServiceBuilderTest extends TestCase { private ServiceBuilder $serviceBuilder; - /** - * @covers \Bitrix24\SDK\Services\ServiceBuilder::getMainScope - */ public function testGetMainScopeBuilder(): void { $this->serviceBuilder->getMainScope(); $this::assertTrue(true); } - /** - * @covers \Bitrix24\SDK\Services\ServiceBuilder::getIMScope - */ public function testGetIMScopeBuilder(): void { $this->serviceBuilder->getIMScope(); $this::assertTrue(true); } - /** - * @covers \Bitrix24\SDK\Services\ServiceBuilder::getCRMScope - */ public function testGetCrmScopeBuilder(): void { $this->serviceBuilder->getCRMScope(); $this::assertTrue(true); } - public function setUp(): void + protected function setUp(): void { $this->serviceBuilder = new ServiceBuilder( new NullCore(), diff --git a/tests/Unit/Stubs/NullBatch.php b/tests/Unit/Stubs/NullBatch.php index 7781fa6f..fc6b0a7c 100644 --- a/tests/Unit/Stubs/NullBatch.php +++ b/tests/Unit/Stubs/NullBatch.php @@ -6,24 +6,16 @@ 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 DateTimeImmutable; use Generator; -/** - * Class NullCore - * - * @package Bitrix24\SDK\Tests\Unit\Stubs - */ class NullBatch implements BatchOperationsInterface { /** - * @param string $apiMethod - * @param array $order - * @param array $filter - * @param array $select - * @param int|null $limit - * @param array|null $additionalParameters * @inheritDoc */ public function getTraversableList(string $apiMethod, array $order, array $filter, array $select, ?int $limit = null, ?array $additionalParameters = null): Generator @@ -49,7 +41,7 @@ public function getTraversableListWithCount( */ public function addEntityItems(string $apiMethod, array $entityItems): Generator { - yield []; + yield new ResponseData([],new Time(0,0,0,0,0, new DateTimeImmutable(),new DateTimeImmutable(),0,),new Pagination()); } /** @@ -57,7 +49,7 @@ public function addEntityItems(string $apiMethod, array $entityItems): Generator */ public function deleteEntityItems(string $apiMethod, array $entityItemId): Generator { - yield []; + yield new ResponseData([],new Time(0,0,0,0,0, new DateTimeImmutable(),new DateTimeImmutable(),0,),new Pagination()); } /** @@ -65,6 +57,6 @@ public function deleteEntityItems(string $apiMethod, array $entityItemId): Gener */ public function updateEntityItems(string $apiMethod, array $entityItems): Generator { - yield []; + yield new ResponseData([],new Time(0,0,0,0,0, new DateTimeImmutable(),new DateTimeImmutable(),0,),new Pagination()); } } \ No newline at end of file diff --git a/tests/Unit/Stubs/NullCore.php b/tests/Unit/Stubs/NullCore.php index 13d85e00..eadfa259 100644 --- a/tests/Unit/Stubs/NullCore.php +++ b/tests/Unit/Stubs/NullCore.php @@ -20,10 +20,7 @@ class NullCore implements CoreInterface { /** - * @param string $apiMethod - * @param array $parameters * - * @return Response * @throws \Exception */ public function call(string $apiMethod, array $parameters = []): Response From ed0aeda27d0e4628aaf85b6e00629d64a6d680f4 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 7 Jul 2024 11:05:23 +0600 Subject: [PATCH 090/138] Refactor AccessToken to AuthToken in SDK tests The AccessToken and related classes and interfaces have been replaced with AuthToken and relevant entities across the SDK tests. The main aim was to unify the nomenclature and make it more expressive and intuitive. For instance, the AccessTokenFileStorage has been renamed to AuthTokenFileStorage, and methods and variables have been renamed accordingly. Signed-off-by: mesilov --- .../AccessTokenRepositoryInterface.php | 20 ------------- .../ApplicationCredentialsProvider.php | 14 ++++----- ...leStorage.php => AuthTokenFileStorage.php} | 29 ++++++++++--------- tests/ApplicationBridge/index.php | 6 ++-- 4 files changed, 26 insertions(+), 43 deletions(-) delete mode 100644 tests/ApplicationBridge/AccessTokenRepositoryInterface.php rename tests/ApplicationBridge/{AccessTokenFileStorage.php => AuthTokenFileStorage.php} (54%) diff --git a/tests/ApplicationBridge/AccessTokenRepositoryInterface.php b/tests/ApplicationBridge/AccessTokenRepositoryInterface.php deleted file mode 100644 index 217a215d..00000000 --- a/tests/ApplicationBridge/AccessTokenRepositoryInterface.php +++ /dev/null @@ -1,20 +0,0 @@ -repository->isAvailable(); } - public function saveAccessToken(AccessToken $accessToken): void + public function saveAuthToken(AuthToken $authToken): void { - $this->repository->saveAccessToken($accessToken); + $this->repository->saveToken($authToken); } /** @@ -36,7 +36,7 @@ public function getCredentials(ApplicationProfile $applicationProfile, string $d { return new Credentials( null, - $this->repository->getAccessToken(), + $this->repository->getToken(), $applicationProfile, $domainUrl ); @@ -46,11 +46,11 @@ public function getCredentials(ApplicationProfile $applicationProfile, string $d public function onAuthTokenRenewedEventListener(AuthTokenRenewedEvent $event): void { // update credentials - $this->repository->saveRenewedAccessToken($event->getRenewedToken()); + $this->repository->saveRenewedToken($event->getRenewedToken()); } public static function buildProviderForLocalApplication(): self { - return new ApplicationCredentialsProvider(new AccessTokenFileStorage(new Filesystem())); + return new ApplicationCredentialsProvider(new AuthTokenFileStorage(new Filesystem())); } } \ No newline at end of file diff --git a/tests/ApplicationBridge/AccessTokenFileStorage.php b/tests/ApplicationBridge/AuthTokenFileStorage.php similarity index 54% rename from tests/ApplicationBridge/AccessTokenFileStorage.php rename to tests/ApplicationBridge/AuthTokenFileStorage.php index e113ac86..1af6a99e 100644 --- a/tests/ApplicationBridge/AccessTokenFileStorage.php +++ b/tests/ApplicationBridge/AuthTokenFileStorage.php @@ -4,13 +4,13 @@ namespace Bitrix24\SDK\Tests\ApplicationBridge; -use Bitrix24\SDK\Core\Credentials\AccessToken; +use Bitrix24\SDK\Core\Credentials\AuthToken; use Bitrix24\SDK\Core\Exceptions\FileNotFoundException; -use Bitrix24\SDK\Core\Response\DTO\RenewedAccessToken; +use Bitrix24\SDK\Core\Response\DTO\RenewedAuthToken; use JsonException; use Symfony\Component\Filesystem\Filesystem; -readonly class AccessTokenFileStorage implements AccessTokenRepositoryInterface +readonly class AuthTokenFileStorage implements AuthTokenRepositoryInterface { private const TOKEN_FILE_NAME = 'auth.json'; @@ -33,29 +33,32 @@ public function isAvailable(): bool * @throws FileNotFoundException * @throws JsonException */ - public function getAccessToken(): AccessToken + 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 AccessToken::initFromArray(json_decode($payload, true, 512, JSON_THROW_ON_ERROR)); + return AuthToken::initFromArray(json_decode($payload, true, 512, JSON_THROW_ON_ERROR)); } - public function saveAccessToken(AccessToken $accessToken): void + /** + * @throws JsonException + */ + public function saveToken(AuthToken $authToken): void { - $accessTokenPayload = json_encode([ - 'access_token' => $accessToken->getAccessToken(), - 'refresh_token' => $accessToken->getRefreshToken(), - 'expires' => $accessToken->getExpires() + $tokenPayload = json_encode([ + 'access_token' => $authToken->getAccessToken(), + 'refresh_token' => $authToken->getRefreshToken(), + 'expires' => $authToken->getExpires() ], JSON_THROW_ON_ERROR); - $this->filesystem->dumpFile($this->getFileName(), $accessTokenPayload); + $this->filesystem->dumpFile($this->getFileName(), $tokenPayload); } - public function saveRenewedAccessToken(RenewedAccessToken $renewedAccessToken): void + public function saveRenewedToken(RenewedAuthToken $renewedAuthToken): void { - $this->saveAccessToken($renewedAccessToken->getAccessToken()); + $this->saveToken($renewedAuthToken->authToken); } } \ No newline at end of file diff --git a/tests/ApplicationBridge/index.php b/tests/ApplicationBridge/index.php index 5ac9ce4e..90947415 100644 --- a/tests/ApplicationBridge/index.php +++ b/tests/ApplicationBridge/index.php @@ -1,7 +1,7 @@ initFromRequest($appProfile, $accessToken, $_REQUEST['DOMAIN']); // save new access token for integration tests $credentialsProvider = ApplicationCredentialsProvider::buildProviderForLocalApplication(); -$credentialsProvider->saveAccessToken($accessToken); +$credentialsProvider->saveAuthToken($accessToken); // call rest-api print_r($b24Service->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()); From 02e9278f5eb3540f1b5c57d05a707960f4bcbf4f Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 7 Jul 2024 11:06:23 +0600 Subject: [PATCH 091/138] Add AuthTokenRepositoryInterface An interface AuthTokenRepositoryInterface has been added under the ApplicationBridge in tests. At the same time, an unnecessary use statement, AccessTokenFileStorage, has been removed from Fabric.php in Integration tests. Signed-off-by: mesilov --- .../AuthTokenRepositoryInterface.php | 20 +++++++++++++++++++ tests/Integration/Fabric.php | 1 - 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 tests/ApplicationBridge/AuthTokenRepositoryInterface.php diff --git a/tests/ApplicationBridge/AuthTokenRepositoryInterface.php b/tests/ApplicationBridge/AuthTokenRepositoryInterface.php new file mode 100644 index 00000000..8302e31b --- /dev/null +++ b/tests/ApplicationBridge/AuthTokenRepositoryInterface.php @@ -0,0 +1,20 @@ + Date: Sun, 7 Jul 2024 23:25:15 +0600 Subject: [PATCH 092/138] Add Bitrix24Accounts documentation Created a new documentation file for the Bitrix24Accounts in the Application Contracts. This documentation includes an account state diagram and a detailed breakdown of repository methods. Each method is explained with its associated use cases to aid in understanding and implementation. Signed-off-by: mesilov --- .../Bitrix24Accounts/Docs/Bitrix24Accounts.md | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/Application/Contracts/Bitrix24Accounts/Docs/Bitrix24Accounts.md diff --git a/src/Application/Contracts/Bitrix24Accounts/Docs/Bitrix24Accounts.md b/src/Application/Contracts/Bitrix24Accounts/Docs/Bitrix24Accounts.md new file mode 100644 index 00000000..6f49e015 --- /dev/null +++ b/src/Application/Contracts/Bitrix24Accounts/Docs/Bitrix24Accounts.md @@ -0,0 +1,40 @@ +# Bitrix24 account entity + +## Bitrix24 account state diagram + +```mermaid +stateDiagram-v2 + [*] --> New: New Bitrix24 account\nwhen installation started + New --> Active : Installation completed succesfuly + New --> Blocked : Installation aborted + Active --> Blocked : Connection lost or\nForcibly deactivated + Active --> Deleted : Application\n uninstalled + Blocked --> Active : Reconnected or\nReactivated + Deleted --> [*]: Bitrix24 account can be removed\n from persistnce storage +``` + + +## Repository methods + +- `save(Bitrix24Accounts\Entity\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): Bitrix24Accounts\Entity\Bitrix24AccountInterface` + - use case Activate + - use case Block +- `delete(Bitrix24AccountInterface $entity): void` + - use case Uninstall +- `findByMemberId(string $memberId, ?Bitrix24AccountStatus $status = null): array` + - use case InstallStart + - use case InstallFinish + - use case RenewAuthToken + - use case Uninstall + - use case UpdateVersion (как быть при множественных токенах при обновлении у админа?) +- `findByDomainUrl(string $domainUrl): array` + - use case ChangeDomainUrl From c98cbd7025067a87ab0c1279e5433f1734f74271 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 7 Jul 2024 23:25:51 +0600 Subject: [PATCH 093/138] Add Bitrix24Accounts documentation Created a new documentation file for the Bitrix24Accounts in the Application Contracts. This documentation includes an account state diagram and a detailed breakdown of repository methods. Each method is explained with its associated use cases to aid in understanding and implementation. Signed-off-by: mesilov --- .../Exceptions/Bitrix24AccountNotFoundException.php | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/Application/Contracts/Bitrix24Accounts/Exceptions/Bitrix24AccountNotFoundException.php diff --git a/src/Application/Contracts/Bitrix24Accounts/Exceptions/Bitrix24AccountNotFoundException.php b/src/Application/Contracts/Bitrix24Accounts/Exceptions/Bitrix24AccountNotFoundException.php new file mode 100644 index 00000000..c785f261 --- /dev/null +++ b/src/Application/Contracts/Bitrix24Accounts/Exceptions/Bitrix24AccountNotFoundException.php @@ -0,0 +1,11 @@ + Date: Mon, 8 Jul 2024 01:37:50 +0600 Subject: [PATCH 094/138] Update Bitrix24AccountRepositoryInterface with new methods This commit expands the Bitrix24AccountRepositoryInterface with new methods for handling Bitrix24 accounts. It includes methods for saving and deleting Bitrix24 accounts, and for fetching accounts by id or specific characteristics. This update provides enhanced functionality to interact with Bitrix24 account data, from basic CRUD operations to more granular lookups based on account status and attributes. Signed-off-by: mesilov --- phpunit.xml.dist | 1 + .../Bitrix24Accounts/Docs/Bitrix24Accounts.md | 81 +- .../Bitrix24AccountRepositoryInterface.php | 41 +- ...Bitrix24AccountRepositoryInterfaceTest.php | 861 ++++++++++++++++++ ...itrix24AccountRepositoryImplementation.php | 143 +++ ...x24AccountRepositoryImplementationTest.php | 59 ++ 6 files changed, 1154 insertions(+), 32 deletions(-) create mode 100644 tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterfaceTest.php create mode 100644 tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementation.php create mode 100644 tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementationTest.php diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 3cdf6e26..5b634897 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -7,6 +7,7 @@ ./tests/Unit ./tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php + ./tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterfaceTest.php ./tests/Integration diff --git a/src/Application/Contracts/Bitrix24Accounts/Docs/Bitrix24Accounts.md b/src/Application/Contracts/Bitrix24Accounts/Docs/Bitrix24Accounts.md index 6f49e015..ff433ada 100644 --- a/src/Application/Contracts/Bitrix24Accounts/Docs/Bitrix24Accounts.md +++ b/src/Application/Contracts/Bitrix24Accounts/Docs/Bitrix24Accounts.md @@ -1,40 +1,65 @@ # Bitrix24 account entity +| 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 Bitrix24 account\nwhen installation started - New --> Active : Installation completed succesfuly + [*] --> New: New account when\ninstallation started + New --> Active : Installation completed successfully New --> Blocked : Installation aborted - Active --> Blocked : Connection lost or\nForcibly deactivated + Active --> Blocked : Connection lost or\nforcibly deactivated Active --> Deleted : Application\n uninstalled - Blocked --> Active : Reconnected or\nReactivated - Deleted --> [*]: Bitrix24 account can be removed\n from persistnce storage + Blocked --> Active : Reconnected or\nreactivated + Blocked --> Deleted : Delete blocked account + Deleted --> [*]: Account can be removed\n from persistence storage ``` - ## Repository methods -- `save(Bitrix24Accounts\Entity\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): Bitrix24Accounts\Entity\Bitrix24AccountInterface` - - use case Activate - - use case Block -- `delete(Bitrix24AccountInterface $entity): void` - - use case Uninstall -- `findByMemberId(string $memberId, ?Bitrix24AccountStatus $status = null): array` - - use case InstallStart - - use case InstallFinish - - use case RenewAuthToken - - use case Uninstall - - use case UpdateVersion (как быть при множественных токенах при обновлении у админа?) -- `findByDomainUrl(string $domainUrl): array` - - use case ChangeDomainUrl +- `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` diff --git a/src/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterface.php b/src/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterface.php index 4d2a6361..7ba5c82f 100644 --- a/src/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterface.php +++ b/src/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterface.php @@ -5,17 +5,50 @@ 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 { /** - * Get Bitrix24 account by id + * Save bitrix24 account to persistence storage */ - public function getById(Uuid $uuid): Bitrix24Accounts\Entity\Bitrix24AccountInterface; + public function save(Bitrix24AccountInterface $bitrix24Account): void; /** - * @param bool $isFlush save entity to storage, commit transaction in oltp database + * Delete bitrix24 account from + * @throws Bitrix24AccountNotFoundException + * @throws InvalidArgumentException */ - public function save(Bitrix24Accounts\Entity\Bitrix24AccountInterface $bitrix24Account, bool $isFlush = false): void; + 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 + * @return Bitrix24AccountInterface|null + */ + 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 $status = 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 $status = null, ?bool $isAdmin = null): array; } \ No newline at end of file diff --git a/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterfaceTest.php b/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterfaceTest.php new file mode 100644 index 00000000..0205a0fb --- /dev/null +++ b/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterfaceTest.php @@ -0,0 +1,861 @@ +createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + + $repo = $this->createBitrix24AccountRepositoryImplementation(); + + $repo->save($newB24Account); + $acc = $repo->getById($newB24Account->getId()); + $this->assertEquals($newB24Account, $acc); + } + + #[Test] + #[TestDox('test getById method with non existing account')] + public function testGetByIdNotExists(): void + { + $this->expectException(Bitrix24AccountNotFoundException::class); + $repo = $this->createBitrix24AccountRepositoryImplementation(); + $repo->getById(Uuid::v7()); + } + + /** + * @throws InvalidArgumentException + * @throws Bitrix24AccountNotFoundException + */ + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test delete method for happy path')] + final public function testDeleteHappyPath( + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $repo = $this->createBitrix24AccountRepositoryImplementation(); + + // application installed + $applicationToken = 'application_token'; + $newB24Account->applicationInstalled($applicationToken); + $repo->save($newB24Account); + + // a few moments later + $account = $repo->getById($id); + $account->applicationUninstalled($applicationToken); + $repo->save($newB24Account); + + $repo->delete($id); + + $this->expectException(Bitrix24AccountNotFoundException::class); + $repo->getById($id); + } + + /** + * @throws Bitrix24AccountNotFoundException + */ + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test delete method for account not in deleted state')] + final public function testDeleteNotInDeletedState( + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + + $repo = $this->createBitrix24AccountRepositoryImplementation(); + + $repo->save($newB24Account); + $acc = $repo->getById($id); + $this->assertEquals($newB24Account, $acc); + + $this->expectException(InvalidArgumentException::class); + $repo->delete($id); + } + + /** + * @throws InvalidArgumentException + */ + #[Test] + #[TestDox('test delete method with non existing account')] + public function testDeleteWithIdNotExists(): void + { + $this->expectException(Bitrix24AccountNotFoundException::class); + $repo = $this->createBitrix24AccountRepositoryImplementation(); + $repo->delete(Uuid::v7()); + } + + #[Test] + #[TestDox('test findOneAdminByMemberId method with empty member_id')] + public function testFindOneAdminByMemberIdWithEmptyArgs(): void + { + $repo = $this->createBitrix24AccountRepositoryImplementation(); + $this->expectException(InvalidArgumentException::class); + /** @phpstan-ignore-next-line */ + $repo->findOneAdminByMemberId(''); + } + + /** + * @throws Bitrix24AccountNotFoundException + */ + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test findOneAdminByMemberId method with happy path')] + final public function testFindOneAdminByMemberIdWithHappyPath( + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $repo = $this->createBitrix24AccountRepositoryImplementation(); + + $repo->save($newB24Account); + $acc = $repo->getById($id); + $this->assertEquals($newB24Account, $acc); + + + $found = $repo->findOneAdminByMemberId($memberId); + $this->assertEquals($acc, $found); + } + + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test findOneAdminByMemberId method with simple user')] + final public function testFindOneAdminByMemberIdWithSimpleUser( + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, false, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $repo = $this->createBitrix24AccountRepositoryImplementation(); + + $repo->save($newB24Account); + $acc = $repo->getById($id); + $this->assertEquals($newB24Account, $acc); + + $found = $repo->findOneAdminByMemberId($memberId); + $this->assertNull($found); + } + + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test findByMemberId method with happy path')] + final public function testFindByMemberIdWithHappyPath( + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $repo = $this->createBitrix24AccountRepositoryImplementation(); + + $repo->save($newB24Account); + $acc = $repo->getById($id); + $this->assertEquals($newB24Account, $acc); + + $found = $repo->findByMemberId($memberId); + $this->assertEquals($newB24Account, $found[0]); + } + + #[Test] + #[TestDox('test findByMemberId method with happy path - not found')] + final public function testFindByMemberIdWithHappyPathNotFound(): void + { + $repo = $this->createBitrix24AccountRepositoryImplementation(); + $found = $repo->findByMemberId('member_id'); + $this->assertEquals([], $found); + } + + #[Test] + #[TestDox('test findByMemberId method with empty member id')] + final public function testFindByMemberIdWithEmptyMemberId(): void + { + $repo = $this->createBitrix24AccountRepositoryImplementation(); + $this->expectException(InvalidArgumentException::class); + /** @phpstan-ignore-next-line */ + $repo->findByMemberId(''); + } + + /** + * @throws Bitrix24AccountNotFoundException + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test findByMemberId method with blocked account happy path')] + final public function testFindByMemberIdWithBlockedAccountHappyPath( + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $repo = $this->createBitrix24AccountRepositoryImplementation(); + + $repo->save($newB24Account); + $acc = $repo->getById($id); + $this->assertEquals($newB24Account, $acc); + $acc->markAsBlocked('block by admin'); + $repo->save($acc); + + $found = $repo->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 $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $repo = $this->createBitrix24AccountRepositoryImplementation(); + + $repo->save($newB24Account); + $acc = $repo->getById($id); + $this->assertEquals($newB24Account, $acc); + + $found = $repo->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 $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $repo = $this->createBitrix24AccountRepositoryImplementation(); + + $repo->save($newB24Account); + $acc = $repo->getById($id); + $this->assertEquals($newB24Account, $acc); + + $found = $repo->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 $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, false, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $repo = $this->createBitrix24AccountRepositoryImplementation(); + + $repo->save($newB24Account); + $acc = $repo->getById($id); + $this->assertEquals($newB24Account, $acc); + + $found = $repo->findByMemberId($memberId, null, true); + $this->assertEquals([], $found); + } + + /** + * @throws Bitrix24AccountNotFoundException + */ + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test findByMemberId method with all args')] + final public function testFindByMemberIdWithAllArgs( + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, false, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $repo = $this->createBitrix24AccountRepositoryImplementation(); + + $repo->save($newB24Account); + $acc = $repo->getById($id); + $this->assertEquals($newB24Account, $acc); + + $found = $repo->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 $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $repo = $this->createBitrix24AccountRepositoryImplementation(); + + $repo->save($newB24Account); + $acc = $repo->getById($id); + $this->assertEquals($newB24Account, $acc); + + $found = $repo->findByDomain($domainUrl); + $this->assertEquals($newB24Account, $found[0]); + } + + #[Test] + #[TestDox('test findByDomain method with happy path - not found')] + final public function testFindByDomainWithHappyPathNotFound(): void + { + $repo = $this->createBitrix24AccountRepositoryImplementation(); + $found = $repo->findByDomain('test.com'); + $this->assertEquals([], $found); + } + + #[Test] + #[TestDox('test findByDomain method with empty domain url')] + final public function testFindByDomainWithEmptyDomainUrl(): void + { + $repo = $this->createBitrix24AccountRepositoryImplementation(); + $this->expectException(InvalidArgumentException::class); + /** @phpstan-ignore-next-line */ + $repo->findByDomain(''); + } + + /** + * @throws Bitrix24AccountNotFoundException + * @throws InvalidArgumentException + */ + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test findByDomain method with blocked account happy path')] + final public function testFindByDomainWithBlockedAccountHappyPath( + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $repo = $this->createBitrix24AccountRepositoryImplementation(); + + $repo->save($newB24Account); + $acc = $repo->getById($id); + $this->assertEquals($newB24Account, $acc); + $acc->markAsBlocked('block by admin'); + $repo->save($acc); + + $found = $repo->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 $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $repo = $this->createBitrix24AccountRepositoryImplementation(); + + $repo->save($newB24Account); + $acc = $repo->getById($id); + $this->assertEquals($newB24Account, $acc); + + $found = $repo->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 $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $repo = $this->createBitrix24AccountRepositoryImplementation(); + + $repo->save($newB24Account); + $acc = $repo->getById($id); + $this->assertEquals($newB24Account, $acc); + + $found = $repo->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 $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, false, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $repo = $this->createBitrix24AccountRepositoryImplementation(); + + $repo->save($newB24Account); + $acc = $repo->getById($id); + $this->assertEquals($newB24Account, $acc); + + $found = $repo->findByDomain($memberId, null, true); + $this->assertEquals([], $found); + } + + /** + * @throws Bitrix24AccountNotFoundException + */ + #[Test] + #[DataProvider('bitrix24AccountForInstallDataProvider')] + #[TestDox('test findByDomain method with all args')] + final public function testFindByDomainWithAllArgs( + Uuid $id, + int $bitrix24UserId, + bool $isBitrix24UserAdmin, + string $memberId, + string $domainUrl, + Bitrix24AccountStatus $accountStatus, + AuthToken $authToken, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + int $applicationVersion, + Scope $applicationScope + ): void + { + $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, false, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $repo = $this->createBitrix24AccountRepositoryImplementation(); + + $repo->save($newB24Account); + $acc = $repo->getById($id); + $this->assertEquals($newB24Account, $acc); + + $found = $repo->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/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementation.php b/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementation.php new file mode 100644 index 00000000..f13fe25a --- /dev/null +++ b/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementation.php @@ -0,0 +1,143 @@ +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()]); + + $item = $this->getById($uuid); + if (Bitrix24AccountStatus::deleted !== $item->getStatus()) { + throw new InvalidArgumentException(sprintf('you cannot delete bitrix24account «%s», they must be in status deleted, current status «%s»', + $item->getId()->toRfc4122(), + $item->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 $status = null, ?bool $isAdmin = null): array + { + $this->logger->debug('b24AccountRepository.findByMemberId', [ + 'memberId' => $memberId, + 'status' => $status?->name, + 'isAdmin' => $isAdmin + ]); + + if ($memberId === '') { + throw new InvalidArgumentException('memberId cannot be empty'); + } + + $items = []; + foreach ($this->items as $item) { + if ($item->getMemberId() !== $memberId) { + continue; + } + + $isStatusMatch = ($status === null || $status === $item->getStatus()); + $isAdminMatch = ($isAdmin === null || $isAdmin === $item->isBitrix24UserAdmin()); + + if ($isStatusMatch && $isAdminMatch) { + $items[] = $item; + } + + } + return $items; + } + + /** + * @throws InvalidArgumentException + */ + public function findByDomain(string $domainUrl, ?Bitrix24AccountStatus $status = null, ?bool $isAdmin = null): array + { + $this->logger->debug('b24AccountRepository.findByDomain', [ + 'domain' => $domainUrl, + 'status' => $status?->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 = ($status === null || $status === $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..9e462d2a --- /dev/null +++ b/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementationTest.php @@ -0,0 +1,59 @@ + Date: Mon, 8 Jul 2024 01:51:06 +0600 Subject: [PATCH 095/138] Update Bitrix24Accounts documentation The documentation for Bitrix24Accounts has been revised. A summary line has been added to better provide context and understandability to its content. It now contains a clear brief about storing auth tokens and methods for working with a Bitrix24 account. Signed-off-by: mesilov --- .../Bitrix24Accounts/Docs/Bitrix24Accounts.md | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/src/Application/Contracts/Bitrix24Accounts/Docs/Bitrix24Accounts.md b/src/Application/Contracts/Bitrix24Accounts/Docs/Bitrix24Accounts.md index ff433ada..95d1e44f 100644 --- a/src/Application/Contracts/Bitrix24Accounts/Docs/Bitrix24Accounts.md +++ b/src/Application/Contracts/Bitrix24Accounts/Docs/Bitrix24Accounts.md @@ -1,28 +1,29 @@ # Bitrix24 account entity -| 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. | - | +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 From a362fa3c8a6d5d467485c99878074829d1bae43b Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 11 Jul 2024 02:16:42 +0600 Subject: [PATCH 096/138] Add Bitrix24Account Events and update documentation Signed-off-by: mesilov --- .../Bitrix24Accounts/Docs/Bitrix24Accounts.md | 28 +++++++++++++++++++ ...trix24AccountApplicationInstalledEvent.php | 18 ++++++++++++ ...ix24AccountApplicationUninstalledEvent.php | 19 +++++++++++++ ...4AccountApplicationVersionUpdatedEvent.php | 18 ++++++++++++ .../Events/Bitrix24AccountBlockedEvent.php | 18 ++++++++++++ .../Events/Bitrix24AccountCreatedEvent.php | 18 ++++++++++++ .../Events/Bitrix24AccountDeletedEvent.php | 18 ++++++++++++ .../Bitrix24AccountDomainUrlChangedEvent.php | 18 ++++++++++++ .../Events/Bitrix24AccountUnblockedEvent.php | 18 ++++++++++++ 9 files changed, 173 insertions(+) create mode 100644 src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountApplicationInstalledEvent.php create mode 100644 src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountApplicationUninstalledEvent.php create mode 100644 src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountApplicationVersionUpdatedEvent.php create mode 100644 src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountBlockedEvent.php create mode 100644 src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountCreatedEvent.php create mode 100644 src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountDeletedEvent.php create mode 100644 src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountDomainUrlChangedEvent.php create mode 100644 src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountUnblockedEvent.php diff --git a/src/Application/Contracts/Bitrix24Accounts/Docs/Bitrix24Accounts.md b/src/Application/Contracts/Bitrix24Accounts/Docs/Bitrix24Accounts.md index 95d1e44f..226baef4 100644 --- a/src/Application/Contracts/Bitrix24Accounts/Docs/Bitrix24Accounts.md +++ b/src/Application/Contracts/Bitrix24Accounts/Docs/Bitrix24Accounts.md @@ -64,3 +64,31 @@ stateDiagram-v2 - `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/Events/Bitrix24AccountApplicationInstalledEvent.php b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountApplicationInstalledEvent.php new file mode 100644 index 00000000..f3fabff9 --- /dev/null +++ b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountApplicationInstalledEvent.php @@ -0,0 +1,18 @@ + Date: Sun, 14 Jul 2024 02:35:15 +0600 Subject: [PATCH 097/138] Add contact person entities and interface, update dependencies Added new entities for "FullName" and "ContactPersonStatus", alongside an interface for "ContactPerson" under the Contracts namespace. Also, sample entity implementation has been added for testing purposes only. Dependencies in composer.json have also been updated to include necessary libraries and tools for these new implementations. Signed-off-by: mesilov --- composer.json | 28 +-- .../Entity/ContactPersonInterface.php | 128 ++++++++++++ .../Entity/ContactPersonStatus.php | 12 ++ .../ContactPersons/Entity/FullName.php | 32 +++ ...actPersonReferenceEntityImplementation.php | 182 ++++++++++++++++++ 5 files changed, 371 insertions(+), 11 deletions(-) create mode 100644 src/Application/Contracts/ContactPersons/Entity/ContactPersonInterface.php create mode 100644 src/Application/Contracts/ContactPersons/Entity/ContactPersonStatus.php create mode 100644 src/Application/Contracts/ContactPersons/Entity/FullName.php create mode 100644 tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonReferenceEntityImplementation.php diff --git a/composer.json b/composer.json index 94d969dd..4b936c76 100644 --- a/composer.json +++ b/composer.json @@ -17,17 +17,21 @@ } ], "config": { - "sort-packages": true + "sort-packages": true, + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } }, "require": { "php": "8.2.* || 8.3.*", "ext-json": "*", - "ext-bcmath": "*", "ext-curl": "*", "ext-intl": "*", "psr/log": "^2 || ^3", - "fig/http-message-util": "1.1.*", - "nesbot/carbon": "3.3.*", + "fig/http-message-util": "^1", + "giggsey/libphonenumber-for-php": "^8", + "darsyn/ip": "^4 || ^5", + "nesbot/carbon": "^3", "moneyphp/money": "^3 || ^4", "symfony/http-client": "^6 || ^7", "symfony/console": "^6 || ^7", @@ -40,14 +44,16 @@ "symfony/uid": "^6 || ^7" }, "require-dev": { - "monolog/monolog": "3.5.*", - "phpstan/phpstan": "1.10.*", - "phpunit/phpunit": "11.0.*", - "symfony/debug-bundle": "7.0.*", - "symfony/stopwatch": "7.0.*", + "fakerphp/faker": "^1", + "monolog/monolog": "^3", + "nunomaduro/phpinsights": "^2", + "phpstan/phpstan": "^1", + "phpunit/phpunit": "^10 || ^11", + "psalm/phar": "^5", + "rector/rector": "^1", "roave/security-advisories": "dev-master", - "fakerphp/faker": "1.23.*", - "rector/rector": "^1.0" + "symfony/debug-bundle": "^6 || ^7", + "symfony/stopwatch": "^6 || ^7" }, "autoload": { "psr-4": { diff --git a/src/Application/Contracts/ContactPersons/Entity/ContactPersonInterface.php b/src/Application/Contracts/ContactPersons/Entity/ContactPersonInterface.php new file mode 100644 index 00000000..947af1fd --- /dev/null +++ b/src/Application/Contracts/ContactPersons/Entity/ContactPersonInterface.php @@ -0,0 +1,128 @@ +surname = trim($surname); + } + if ($this->patronymic !== null) { + $this->patronymic = trim($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/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonReferenceEntityImplementation.php b/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonReferenceEntityImplementation.php new file mode 100644 index 00000000..c76af8c9 --- /dev/null +++ b/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonReferenceEntityImplementation.php @@ -0,0 +1,182 @@ +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(); + } + + /** + * @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->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 $mobilePhone, ?bool $isMobilePhoneVerified = null): void + { + $this->mobilePhone = $mobilePhone; + 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 getUserAgent(): ?string + { + return $this->userAgent; + } + + public function getUserAgentReferer(): ?string + { + return $this->userAgentReferer; + } + + public function getUserAgentIp(): ?IP + { + return $this->userAgentIp; + } +} From cca7f4655414e644745b32a91b27ec491c374b11 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 21 Jul 2024 19:46:04 +0600 Subject: [PATCH 098/138] Update DemoDataGenerator and ContactPerson entity methods Expanded the DemoDataGenerator class to improve test data variety. Added additional methods to generate random but realistic data. Created a new ContactPerson entity method for marking a user as deleted, enhancing the functionality for manipulations with user status. Updated corresponding tests to cover new features. Signed-off-by: mesilov --- .../Entity/ContactPersonInterface.php | 6 + .../ContactPersonNotFoundException.php | 11 + tests/Builders/DemoDataGenerator.php | 45 +- ...onInterfaceReferenceImplementationTest.php | 56 ++ .../Entity/ContactPersonInterfaceTest.php | 774 ++++++++++++++++++ ...actPersonReferenceEntityImplementation.php | 15 + 6 files changed, 903 insertions(+), 4 deletions(-) create mode 100644 src/Application/Contracts/ContactPersons/Exceptions/ContactPersonNotFoundException.php create mode 100644 tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceReferenceImplementationTest.php create mode 100644 tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceTest.php diff --git a/src/Application/Contracts/ContactPersons/Entity/ContactPersonInterface.php b/src/Application/Contracts/ContactPersons/Entity/ContactPersonInterface.php index 947af1fd..0392e430 100644 --- a/src/Application/Contracts/ContactPersons/Entity/ContactPersonInterface.php +++ b/src/Application/Contracts/ContactPersons/Entity/ContactPersonInterface.php @@ -36,6 +36,12 @@ public function markAsActive(?string $comment): void; */ 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 */ diff --git a/src/Application/Contracts/ContactPersons/Exceptions/ContactPersonNotFoundException.php b/src/Application/Contracts/ContactPersons/Exceptions/ContactPersonNotFoundException.php new file mode 100644 index 00000000..d6842524 --- /dev/null +++ b/src/Application/Contracts/ContactPersons/Exceptions/ContactPersonNotFoundException.php @@ -0,0 +1,11 @@ +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 { - return '+1-703-740-8301'; + $faker = Faker\Factory::create(); + return new FullName($faker->lastName(), $faker->lastName(), $faker->lastName()); } - public static function getRecordFileUrl():string + + 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 'https://github.com/mesilov/bitrix24-php-sdk/raw/384-update-scope-telephony/tests/Integration/Services/Telephony/call-record-test.mp3'; + return Multi::factory(Faker\Factory::create()->ipv4()); } } \ 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..e8079635 --- /dev/null +++ b/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceReferenceImplementationTest.php @@ -0,0 +1,56 @@ +createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($id, $contactPerson->getId()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test getStatus method')] + final public function testGetStatus( + Uuid $id, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($contactPersonStatus, $contactPerson->getStatus()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test markAsActive method')] + final public function testMarkAsActive( + Uuid $id, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $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 $id, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $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 $id, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $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 $id, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $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 $id, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $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 $id, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals(new FullName($name, $surname, $patronymic), $contactPerson->getFullName()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test changeFullName method')] + final public function testChangeFullName( + Uuid $id, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $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 $id, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $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 $id, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($createdAt, $contactPerson->getCreatedAt()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test getEmail method')] + final public function testGetEmail( + Uuid $id, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($email, $contactPerson->getEmail()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test changeEmail method')] + final public function testChangeEmail( + Uuid $id, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $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 $id, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $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 $id, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($mobilePhone, $contactPerson->getMobilePhone()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test changeMobilePhone method')] + final public function testChangeMobilePhone( + Uuid $id, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $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 $id, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($mobilePhone, $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 $id, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($mobilePhone, $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 $id, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $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 $id, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $uuid = Uuid::v7(); + + $contactPerson->setExternalId($uuid->toRfc4122()); + $this->assertEquals($uuid->toRfc4122(), $contactPerson->getExternalId()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test getExternalId method')] + final public function testGetExternalId( + Uuid $id, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $externalId = null; + $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertNull($contactPerson->getExternalId()); + + $uuid = Uuid::v7(); + $externalId = $uuid->toRfc4122(); + $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($externalId, $contactPerson->getExternalId()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test getUserAgent method')] + final public function testGetUserAgent( + Uuid $id, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($userAgent, $contactPerson->getUserAgent()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test getUserAgentReferer method')] + final public function testGetUserAgentReferer( + Uuid $id, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($userAgentReferer, $contactPerson->getUserAgentReferer()); + } + + #[Test] + #[DataProvider('contactPersonDataProvider')] + #[TestDox('test getUserAgentIp method')] + final public function testGetUserAgentIp( + Uuid $id, + CarbonImmutable $createdAt, + CarbonImmutable $updatedAt, + ContactPersonStatus $contactPersonStatus, + string $name, + ?string $surname, + ?string $patronymic, + ?string $email, + ?CarbonImmutable $emailVerifiedAt, + ?string $comment, + ?PhoneNumber $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $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, + DemoDataGenerator::getUserAgent(), + 'https://bitrix24.com/apps/store?utm_source=bx24', + DemoDataGenerator::getUserAgentIp() + ]; + } +} \ 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 index c76af8c9..2ced7e17 100644 --- a/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonReferenceEntityImplementation.php +++ b/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonReferenceEntityImplementation.php @@ -62,6 +62,19 @@ public function markAsActive(?string $comment): void $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 */ @@ -101,6 +114,7 @@ public function getUpdatedAt(): CarbonImmutable public function changeEmail(?string $email, ?bool $isEmailVerified = null): void { + $this->emailVerifiedAt = null; $this->email = $email; if ($isEmailVerified === true) { $this->emailVerifiedAt = new CarbonImmutable(); @@ -126,6 +140,7 @@ public function markEmailAsVerified(): void public function changeMobilePhone(?PhoneNumber $mobilePhone, ?bool $isMobilePhoneVerified = null): void { + $this->mobilePhoneVerifiedAt = null; $this->mobilePhone = $mobilePhone; if ($isMobilePhoneVerified === true) { $this->mobilePhoneVerifiedAt = new CarbonImmutable(); From 269db81fc758f9d7c89c43dafdf7224766007047 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 21 Jul 2024 19:47:26 +0600 Subject: [PATCH 099/138] Add InMemoryContactPersonRepositoryImplementation and tests This commit introduces the InMemoryContactPersonRepositoryImplementation class, which provides an in-memory implementation of the ContactPersonRepositoryInterface. It also includes associated unit test cases to ensure that the implementation behaves as expected. This mainly assists developers in the process of testing without needing a real database. Signed-off-by: mesilov --- .../ContactPersonRepositoryInterface.php | 60 +++ .../ContactPersonRepositoryInterfaceTest.php | 468 ++++++++++++++++++ ...yContactPersonRepositoryImplementation.php | 111 +++++ ...tactPersonRepositoryImplementationTest.php | 99 ++++ 4 files changed, 738 insertions(+) create mode 100644 src/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterface.php create mode 100644 tests/Unit/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php create mode 100644 tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementation.php create mode 100644 tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementationTest.php diff --git a/src/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterface.php b/src/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterface.php new file mode 100644 index 00000000..5b67f494 --- /dev/null +++ b/src/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterface.php @@ -0,0 +1,60 @@ +createContactPersonRepositoryImplementation(); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + + $repo->save($contactPerson); + $acc = $repo->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 $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $repo = $this->createContactPersonRepositoryImplementation(); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + + $repo->save($contactPerson); + $contactPerson = $repo->getById($contactPerson->getId()); + $contactPerson->markAsDeleted('soft delete account'); + $repo->delete($contactPerson->getId()); + + $this->expectException(ContactPersonNotFoundException::class); + $repo->getById($contactPerson->getId()); + } + + #[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 $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $repo = $this->createContactPersonRepositoryImplementation(); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + + $this->expectException(ContactPersonNotFoundException::class); + $repo->delete($contactPerson->getId()); + } + + #[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 $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $repo = $this->createContactPersonRepositoryImplementation(); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + + $repo->save($contactPerson); + $acc = $repo->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 $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $repo = $this->createContactPersonRepositoryImplementation(); + + $this->expectException(ContactPersonNotFoundException::class); + $repo->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 $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $repo = $this->createContactPersonRepositoryImplementation(); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + + $repo->save($contactPerson); + $contactPersons = $repo->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 $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $repo = $this->createContactPersonRepositoryImplementation(); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + + $repo->save($contactPerson); + $contactPersons = $repo->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 $mobilePhone, + ?CarbonImmutable $mobilePhoneVerifiedAt, + ?string $externalId, + ?string $userAgent, + ?string $userAgentReferer, + ?IP $userAgentIp + ): void + { + $repo = $this->createContactPersonRepositoryImplementation(); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + + $repo->save($contactPerson); + $contactPersons = $repo->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 + { + $repo = $this->createContactPersonRepositoryImplementation();$emailToFind = null; + $expectedContactPerson = null; + foreach ($items as $item) { + [$uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp] = $item; + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $repo->save($contactPerson); + if ($expectedContactPerson === null) { + $expectedContactPerson = $contactPerson; + } + } + + $result = $repo->findByEmail($expectedContactPerson->getEmail()); + $this->assertCount(1, $result); + $this->assertEquals($expectedContactPerson, $result[0]); + + } + + public static function contactPersonManyAccountsDataProvider(): Generator + { + $fullName = DemoDataGenerator::getFullName(); + + 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, + 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(), + CarbonImmutable::now(), + 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(), + CarbonImmutable::now(), + 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, + 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, + 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, + 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, + DemoDataGenerator::getUserAgent(), + 'https://bitrix24.com/apps/store?utm_source=bx24', + DemoDataGenerator::getUserAgentIp() + ]; + } +} \ No newline at end of file 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..31a332db --- /dev/null +++ b/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementation.php @@ -0,0 +1,111 @@ +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()]); + + $item = $this->getById($uuid); + if (ContactPersonStatus::deleted !== $item->getStatus()) { + throw new InvalidArgumentException(sprintf('you cannot delete contact person «%s», in status «%s», mark contact person as deleted before', + $item->getId()->toRfc4122(), + $item->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 $status = null, ?bool $isEmailVerified = null): array + { + $result = []; + foreach ($this->items as $contactPerson) { + if ($email !== $contactPerson->getEmail()) { + continue; + } + if ($status !== null && $status !== $contactPerson->getStatus()) { + continue; + } + if ($isEmailVerified !== null && $isEmailVerified !== ($contactPerson->getEmailVerifiedAt() !== null)) { + continue; + } + $result[] = $contactPerson; + } + return $result; + } + + public function findByPhone(PhoneNumber $phoneNumber, ?ContactPersonStatus $status = null, ?bool $isPhoneVerified = null): array + { + $result = []; + foreach ($this->items as $contactPerson) { + if ($phoneNumber !== $contactPerson->getMobilePhone()) { + continue; + } + if ($status !== null && $status !== $contactPerson->getStatus()) { + continue; + } + if ($isPhoneVerified !== null && $isPhoneVerified !== ($contactPerson->getMobilePhoneVerifiedAt() !== null)) { + continue; + } + $result[] = $contactPerson; + } + return $result; + } + + public function findByExternalId(string $externalId): ?ContactPersonInterface + { + $result = null; + foreach ($this->items as $contactPerson) { + if ($externalId === $contactPerson->getExternalId()) { + $result = $contactPerson; + break; + } + } + 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..5bf7f57f --- /dev/null +++ b/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementationTest.php @@ -0,0 +1,99 @@ + Date: Mon, 22 Jul 2024 01:03:48 +0600 Subject: [PATCH 100/138] Update method calls in InfoCallTest Updated method calls in InfoCall tests to use `getNationalNumber()` from `DemoDataGenerator::getMobilePhone()`. This change ensures we're passing the correct format of mobile phone number to `startWithText` and `startWithSound` methods. Signed-off-by: mesilov --- .../Telephony/Voximplant/InfoCall/Service/InfoCallTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Integration/Services/Telephony/Voximplant/InfoCall/Service/InfoCallTest.php b/tests/Integration/Services/Telephony/Voximplant/InfoCall/Service/InfoCallTest.php index e0530647..0785e5ff 100644 --- a/tests/Integration/Services/Telephony/Voximplant/InfoCall/Service/InfoCallTest.php +++ b/tests/Integration/Services/Telephony/Voximplant/InfoCall/Service/InfoCallTest.php @@ -37,7 +37,7 @@ public function tesStartWithText(): void $this->assertTrue($this->infoCall->startWithText( $lines[0]->LINE_ID, - DemoDataGenerator::getMobilePhone(), + DemoDataGenerator::getMobilePhone()->getNationalNumber(), 'test message' )->getCallResult()->RESULT); } @@ -53,7 +53,7 @@ public function tesStartWithSound(): void $this->assertTrue($this->infoCall->startWithSound( $lines[0]->LINE_ID, - DemoDataGenerator::getMobilePhone(), + DemoDataGenerator::getMobilePhone()->getNationalNumber(), DemoDataGenerator::getRecordFileUrl() )->getCallResult()->RESULT); } From 0e9e09129472fbefc963f0a34053675b987529c2 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 22 Jul 2024 01:14:26 +0600 Subject: [PATCH 101/138] Refactor code for improved readability and consistency A variety of changes have been made across several files to enhance readability and optimize semantics. This includes implementing the Stringable interface in the FullName class and cleaning up variable names to be more descriptive. Additionally, unnecessary comments have been removed and elements in the Scope class are now transformed to lowercase in a more concise way. Signed-off-by: mesilov --- .../Bitrix24AccountRepositoryInterface.php | 5 ++--- .../ContactPersons/Entity/ContactPersonInterface.php | 12 ++---------- .../Contracts/ContactPersons/Entity/FullName.php | 7 +++++-- .../Repository/ContactPersonRepositoryInterface.php | 10 ++-------- src/Core/Batch.php | 10 +++++----- src/Core/Credentials/Scope.php | 2 +- 6 files changed, 17 insertions(+), 29 deletions(-) diff --git a/src/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterface.php b/src/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterface.php index 7ba5c82f..e0d01d56 100644 --- a/src/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterface.php +++ b/src/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterface.php @@ -34,7 +34,6 @@ public function getById(Uuid $uuid): Bitrix24AccountInterface; /** * Find one admin bitrix24 account by member_id * @param non-empty-string $memberId - * @return Bitrix24AccountInterface|null */ public function findOneAdminByMemberId(string $memberId): ?Bitrix24AccountInterface; @@ -43,12 +42,12 @@ public function findOneAdminByMemberId(string $memberId): ?Bitrix24AccountInterf * @param non-empty-string $memberId * @return Bitrix24AccountInterface[] */ - public function findByMemberId(string $memberId, ?Bitrix24AccountStatus $status = null, ?bool $isAdmin = null): array; + 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 $status = null, ?bool $isAdmin = null): array; + public function findByDomain(string $domainUrl, ?Bitrix24AccountStatus $bitrix24AccountStatus = null, ?bool $isAdmin = null): array; } \ No newline at end of file diff --git a/src/Application/Contracts/ContactPersons/Entity/ContactPersonInterface.php b/src/Application/Contracts/ContactPersons/Entity/ContactPersonInterface.php index 0392e430..03b45af6 100644 --- a/src/Application/Contracts/ContactPersons/Entity/ContactPersonInterface.php +++ b/src/Application/Contracts/ContactPersons/Entity/ContactPersonInterface.php @@ -42,6 +42,7 @@ public function markAsBlocked(?string $comment): void; * @throws InvalidArgumentException */ public function markAsDeleted(?string $comment): void; + /** * @return FullName return contact person full name */ @@ -64,11 +65,6 @@ public function getUpdatedAt(): CarbonImmutable; */ public function getEmail(): ?string; - /** - * @param string|null $email - * @param bool|null $isEmailVerified - * @return void - */ public function changeEmail(?string $email, ?bool $isEmailVerified = null): void; /** @@ -83,12 +79,8 @@ public function getEmailVerifiedAt(): ?CarbonImmutable; /** * Change mobile phone for contact person - * - * @param PhoneNumber|null $mobilePhone - * @param bool|null $isMobilePhoneVerified - * @return void */ - public function changeMobilePhone(?PhoneNumber $mobilePhone, ?bool $isMobilePhoneVerified = null): void; + public function changeMobilePhone(?PhoneNumber $phoneNumber, ?bool $isMobilePhoneVerified = null): void; public function getMobilePhone(): ?PhoneNumber; diff --git a/src/Application/Contracts/ContactPersons/Entity/FullName.php b/src/Application/Contracts/ContactPersons/Entity/FullName.php index 8dfc1de5..18892be2 100644 --- a/src/Application/Contracts/ContactPersons/Entity/FullName.php +++ b/src/Application/Contracts/ContactPersons/Entity/FullName.php @@ -4,7 +4,9 @@ namespace Bitrix24\SDK\Application\Contracts\ContactPersons\Entity; -class FullName +use Stringable; + +class FullName implements Stringable { public function __construct( public string $name, @@ -15,8 +17,9 @@ public function __construct( if ($surname !== null) { $this->surname = trim($surname); } + if ($this->patronymic !== null) { - $this->patronymic = trim($patronymic); + $this->patronymic = trim((string) $patronymic); } } diff --git a/src/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterface.php b/src/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterface.php index 5b67f494..0a38fd97 100644 --- a/src/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterface.php +++ b/src/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterface.php @@ -35,26 +35,20 @@ public function getById(Uuid $uuid): ContactPersonInterface; /** * Find contact persons with email and filter by status and isEmailVerified flag * @param non-empty-string $email - * @param ContactPersonStatus|null $status - * @param bool|null $isEmailVerified * @return ContactPersonInterface[] */ - public function findByEmail(string $email, ?ContactPersonStatus $status = null, ?bool $isEmailVerified = null): array; + public function findByEmail(string $email, ?ContactPersonStatus $contactPersonStatus = null, ?bool $isEmailVerified = null): array; /** * Find contact persons with PhoneNumber and filter by status and isEmailVerified flag - * @param PhoneNumber $phoneNumber - * @param ContactPersonStatus|null $status - * @param bool|null $isPhoneVerified * @return ContactPersonInterface[] */ - public function findByPhone(PhoneNumber $phoneNumber, ?ContactPersonStatus $status = null, ?bool $isPhoneVerified = null): array; + public function findByPhone(PhoneNumber $phoneNumber, ?ContactPersonStatus $contactPersonStatus = null, ?bool $isPhoneVerified = null): array; /** * Find contact person by external id * * @param non-empty-string $externalId - * @return ContactPersonInterface|null */ public function findByExternalId(string $externalId): ?ContactPersonInterface; } \ No newline at end of file diff --git a/src/Core/Batch.php b/src/Core/Batch.php index 38d1f540..04314109 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -390,15 +390,15 @@ public function getTraversableList( $keyId = $isCrmItemsInBatch ? 'id' : 'ID'; - $firstResultPage = $this->core->call($apiMethod, $params); - $totalElementsCount = $firstResultPage->getResponseData()->getPagination()->getTotal(); + $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 ($firstResultPage->getResponseData()->getResult() as $listElement) { + foreach ($response->getResponseData()->getResult() as $listElement) { ++$elementsCounter; if ($limit !== null && $elementsCounter > $limit) { return; @@ -416,7 +416,7 @@ public function getTraversableList( // return first page $lastElementIdInFirstPage = null; if ($isCrmItemsInBatch) { - foreach ($firstResultPage->getResponseData()->getResult()['items'] as $listElement) { + foreach ($response->getResponseData()->getResult()['items'] as $listElement) { ++$elementsCounter; $lastElementIdInFirstPage = (int)$listElement[$keyId]; if ($limit !== null && $elementsCounter > $limit) { @@ -426,7 +426,7 @@ public function getTraversableList( yield $listElement; } } else { - foreach ($firstResultPage->getResponseData()->getResult() as $listElement) { + foreach ($response->getResponseData()->getResult() as $listElement) { ++$elementsCounter; $lastElementIdInFirstPage = (int)$listElement[$keyId]; if ($limit !== null && $elementsCounter > $limit) { diff --git a/src/Core/Credentials/Scope.php b/src/Core/Credentials/Scope.php index b280269a..ca7671e0 100644 --- a/src/Core/Credentials/Scope.php +++ b/src/Core/Credentials/Scope.php @@ -83,7 +83,7 @@ class Scope */ public function __construct(array $scope = []) { - $scope = array_unique(array_map('strtolower', $scope)); + $scope = array_unique(array_map(strtolower(...), $scope)); sort($scope); if (count($scope) === 1 && $scope[0] === '') { $scope = []; From 48d9e99f2a9d38f230134449542388c039800220 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 22 Jul 2024 01:17:21 +0600 Subject: [PATCH 102/138] Refactor variable names for better clarity This commit refactors several variable names across multiple methods in the codebase to increase readability. Changes include renaming "item" to "contactPerson", "userRepository" to "userRepo", "mobilePhone" to "phoneNumber" among others. The objective is to ensure that the names are meaningful and accurately reflect their purpose within the code. Signed-off-by: mesilov --- .../Entity/Bitrix24AccountInterfaceTest.php | 140 ++++---- ...Bitrix24AccountRepositoryInterfaceTest.php | 327 +++++++++--------- ...itrix24AccountRepositoryImplementation.php | 24 +- ...onInterfaceReferenceImplementationTest.php | 4 +- .../Entity/ContactPersonInterfaceTest.php | 166 ++++----- ...actPersonReferenceEntityImplementation.php | 6 +- .../ContactPersonRepositoryInterfaceTest.php | 89 ++--- ...yContactPersonRepositoryImplementation.php | 49 ++- ...tactPersonRepositoryImplementationTest.php | 4 +- 9 files changed, 422 insertions(+), 387 deletions(-) diff --git a/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php index 03b4e5c2..defb1109 100644 --- a/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php +++ b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php @@ -43,12 +43,12 @@ abstract protected function createBitrix24AccountImplementation( #[DataProvider('bitrix24AccountDataProvider')] #[TestDox('test getId method')] final public function testGetId( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -56,20 +56,20 @@ final public function testGetId( Scope $applicationScope ): void { - $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $this->assertEquals($id, $bitrix24Account->getId()); + $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 $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -77,7 +77,7 @@ final public function testGetBitrix24UserId( Scope $applicationScope ): void { - $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); $this->assertEquals($bitrix24UserId, $bitrix24Account->getBitrix24UserId()); } @@ -85,12 +85,12 @@ final public function testGetBitrix24UserId( #[DataProvider('bitrix24AccountDataProvider')] #[TestDox('test isBitrix24UserAdmin method')] final public function testisBitrix24UserAdmin( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -98,7 +98,7 @@ final public function testisBitrix24UserAdmin( Scope $applicationScope ): void { - $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); $this->assertEquals($isBitrix24UserAdmin, $bitrix24Account->isBitrix24UserAdmin()); } @@ -106,12 +106,12 @@ final public function testisBitrix24UserAdmin( #[DataProvider('bitrix24AccountDataProvider')] #[TestDox('test getMemberId method')] final public function testGetMemberId( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -119,7 +119,7 @@ final public function testGetMemberId( Scope $applicationScope ): void { - $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); $this->assertEquals($memberId, $bitrix24Account->getMemberId()); } @@ -127,12 +127,12 @@ final public function testGetMemberId( #[DataProvider('bitrix24AccountDataProvider')] #[TestDox('test getDomainUrl method')] final public function testGetDomainUrl( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -140,7 +140,7 @@ final public function testGetDomainUrl( Scope $applicationScope ): void { - $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); $this->assertEquals($domainUrl, $bitrix24Account->getDomainUrl()); } @@ -148,12 +148,12 @@ final public function testGetDomainUrl( #[DataProvider('bitrix24AccountDataProvider')] #[TestDox('test getStatus method')] final public function testGetStatus( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -161,20 +161,20 @@ final public function testGetStatus( Scope $applicationScope ): void { - $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $this->assertEquals($accountStatus, $bitrix24Account->getStatus()); + $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 $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -182,7 +182,7 @@ final public function testGetAuthToken( Scope $applicationScope ): void { - $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); $this->assertEquals($authToken, $bitrix24Account->getAuthToken()); } @@ -190,12 +190,12 @@ final public function testGetAuthToken( #[DataProvider('bitrix24AccountDataProvider')] #[TestDox('test renewAuthToken method')] final public function testRenewAuthToken( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -203,16 +203,16 @@ final public function testRenewAuthToken( Scope $applicationScope ): void { - $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); $newAuthToken = new AuthToken('access_token-2', 'refresh_token=2', 1609459202); - $appStatus = ApplicationStatus::subscription(); + $applicationStatus = ApplicationStatus::subscription(); $renewedAuthToken = new RenewedAuthToken( $newAuthToken, $memberId, 'https://bitrix24.com/client', 'https://bitrix24.com/server', - $appStatus, + $applicationStatus, $domainUrl ); $bitrix24Account->renewAuthToken($renewedAuthToken); @@ -225,12 +225,12 @@ final public function testRenewAuthToken( #[DataProvider('bitrix24AccountDataProvider')] #[TestDox('test getApplicationVersion method')] final public function testGetApplicationVersion( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -238,7 +238,7 @@ final public function testGetApplicationVersion( Scope $applicationScope ): void { - $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); $this->assertEquals($applicationVersion, $bitrix24Account->getApplicationVersion()); } @@ -247,12 +247,12 @@ final public function testGetApplicationVersion( #[DataProvider('bitrix24AccountDataProvider')] #[TestDox('test getApplicationScope method')] final public function testGetApplicationScope( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -260,7 +260,7 @@ final public function testGetApplicationScope( Scope $applicationScope ): void { - $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); $this->assertEquals($applicationScope, $bitrix24Account->getApplicationScope()); } @@ -268,12 +268,12 @@ final public function testGetApplicationScope( #[DataProvider('bitrix24AccountDataProvider')] #[TestDox('test changeDomainUrl method')] final public function testChangeDomainUrl( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -282,9 +282,9 @@ final public function testChangeDomainUrl( ): void { $newDomainUrl = 'new-bitrix24.com'; - $ob = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $ob->changeDomainUrl($newDomainUrl); - $this->assertEquals($newDomainUrl, $ob->getDomainUrl()); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24Account->changeDomainUrl($newDomainUrl); + $this->assertEquals($newDomainUrl, $bitrix24Account->getDomainUrl()); } /** @@ -294,12 +294,12 @@ final public function testChangeDomainUrl( #[DataProvider('bitrix24AccountForInstallDataProvider')] #[TestDox('test applicationInstalled method')] final public function testApplicationInstalled( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -313,7 +313,7 @@ final public function testApplicationInstalled( $this->expectException($throwable::class); } - $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); $bitrix24Account->applicationInstalled($applicationToken); $this->assertTrue($bitrix24Account->isApplicationTokenValid($applicationToken)); } @@ -322,7 +322,7 @@ final public function testApplicationInstalled( #[DataProvider('bitrix24AccountForUninstallDataProvider')] #[TestDox('test applicationUninstalled method')] final public function testApplicationUninstalled( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, @@ -334,14 +334,14 @@ final public function testApplicationUninstalled( int $applicationVersion, Scope $applicationScope, string $applicationToken, - ?Throwable $exception + ?Throwable $throwable ): void { - if ($exception instanceof \Throwable) { - $this->expectException($exception::class); + if ($throwable instanceof \Throwable) { + $this->expectException($throwable::class); } - $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $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()); @@ -354,7 +354,7 @@ final public function testApplicationUninstalled( #[DataProvider('bitrix24AccountWithStatusNewDataProvider')] #[TestDox('test isApplicationTokenValid method')] final public function testIsApplicationTokenValid( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, @@ -368,7 +368,7 @@ final public function testIsApplicationTokenValid( string $applicationToken, ): void { - $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $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)); @@ -381,12 +381,12 @@ final public function testIsApplicationTokenValid( #[DataProvider('bitrix24AccountWithStatusNewDataProvider')] #[TestDox('test getCreatedAt method')] final public function testGetCreatedAt( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -395,7 +395,7 @@ final public function testGetCreatedAt( string $applicationToken, ): void { - $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $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)); @@ -408,12 +408,12 @@ final public function testGetCreatedAt( #[DataProvider('bitrix24AccountWithStatusNewDataProvider')] #[TestDox('test getUpdatedAt method')] final public function testGetUpdatedAt( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -422,7 +422,7 @@ final public function testGetUpdatedAt( string $applicationToken, ): void { - $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $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)); @@ -435,12 +435,12 @@ final public function testGetUpdatedAt( #[DataProvider('bitrix24AccountWithStatusNewDataProvider')] #[TestDox('test updateApplicationVersion method')] final public function testUpdateApplicationVersion( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -456,7 +456,7 @@ final public function testUpdateApplicationVersion( $this->expectException($throwable::class); } - $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $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()); @@ -470,26 +470,26 @@ final public function testUpdateApplicationVersion( #[DataProvider('bitrix24AccountForInstallDataProvider')] #[TestDox('test markAsBlocked and getComment methods')] final public function testMarkAsBlocked( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, int $applicationVersion, Scope $applicationScope, string $applicationToken, - ?Throwable $exception + ?Throwable $throwable ): void { - if ($exception instanceof \Throwable) { - $this->expectException($exception::class); + if ($throwable instanceof \Throwable) { + $this->expectException($throwable::class); } - $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); $bitrix24Account->applicationInstalled($applicationToken); $comment = 'block account just for fun'; @@ -505,26 +505,26 @@ final public function testMarkAsBlocked( #[DataProvider('bitrix24AccountForInstallDataProvider')] #[TestDox('test markAsActive and getComment methods')] final public function testMarkAsActive( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, int $applicationVersion, Scope $applicationScope, string $applicationToken, - ?Throwable $exception + ?Throwable $throwable ): void { - if ($exception instanceof \Throwable) { - $this->expectException($exception::class); + if ($throwable instanceof \Throwable) { + $this->expectException($throwable::class); } - $bitrix24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); $bitrix24Account->applicationInstalled($applicationToken); $comment = 'block account just for fun'; diff --git a/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterfaceTest.php b/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterfaceTest.php index 0205a0fb..337724f8 100644 --- a/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterfaceTest.php +++ b/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterfaceTest.php @@ -48,12 +48,12 @@ abstract protected function createBitrix24AccountRepositoryImplementation(): Bit #[DataProvider('bitrix24AccountForInstallDataProvider')] #[TestDox('test save method for install start use case')] final public function testSave( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -61,13 +61,14 @@ final public function testSave( Scope $applicationScope ): void { - $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $repo = $this->createBitrix24AccountRepositoryImplementation(); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); - $repo->save($newB24Account); - $acc = $repo->getById($newB24Account->getId()); - $this->assertEquals($newB24Account, $acc); + $bitrix24AccountRepository->save($bitrix24Account); + + $acc = $bitrix24AccountRepository->getById($bitrix24Account->getId()); + $this->assertEquals($bitrix24Account, $acc); } #[Test] @@ -75,8 +76,8 @@ final public function testSave( public function testGetByIdNotExists(): void { $this->expectException(Bitrix24AccountNotFoundException::class); - $repo = $this->createBitrix24AccountRepositoryImplementation(); - $repo->getById(Uuid::v7()); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + $bitrix24AccountRepository->getById(Uuid::v7()); } /** @@ -87,12 +88,12 @@ public function testGetByIdNotExists(): void #[DataProvider('bitrix24AccountForInstallDataProvider')] #[TestDox('test delete method for happy path')] final public function testDeleteHappyPath( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -100,23 +101,24 @@ final public function testDeleteHappyPath( Scope $applicationScope ): void { - $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $repo = $this->createBitrix24AccountRepositoryImplementation(); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); // application installed $applicationToken = 'application_token'; - $newB24Account->applicationInstalled($applicationToken); - $repo->save($newB24Account); + $bitrix24Account->applicationInstalled($applicationToken); + $bitrix24AccountRepository->save($bitrix24Account); // a few moments later - $account = $repo->getById($id); + $account = $bitrix24AccountRepository->getById($uuid); $account->applicationUninstalled($applicationToken); - $repo->save($newB24Account); - $repo->delete($id); + $bitrix24AccountRepository->save($bitrix24Account); + + $bitrix24AccountRepository->delete($uuid); $this->expectException(Bitrix24AccountNotFoundException::class); - $repo->getById($id); + $bitrix24AccountRepository->getById($uuid); } /** @@ -126,12 +128,12 @@ final public function testDeleteHappyPath( #[DataProvider('bitrix24AccountForInstallDataProvider')] #[TestDox('test delete method for account not in deleted state')] final public function testDeleteNotInDeletedState( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -139,16 +141,17 @@ final public function testDeleteNotInDeletedState( Scope $applicationScope ): void { - $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); - $repo = $this->createBitrix24AccountRepositoryImplementation(); + $bitrix24AccountRepository->save($bitrix24Account); - $repo->save($newB24Account); - $acc = $repo->getById($id); - $this->assertEquals($newB24Account, $acc); + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); $this->expectException(InvalidArgumentException::class); - $repo->delete($id); + $bitrix24AccountRepository->delete($uuid); } /** @@ -159,18 +162,18 @@ final public function testDeleteNotInDeletedState( public function testDeleteWithIdNotExists(): void { $this->expectException(Bitrix24AccountNotFoundException::class); - $repo = $this->createBitrix24AccountRepositoryImplementation(); - $repo->delete(Uuid::v7()); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + $bitrix24AccountRepository->delete(Uuid::v7()); } #[Test] #[TestDox('test findOneAdminByMemberId method with empty member_id')] public function testFindOneAdminByMemberIdWithEmptyArgs(): void { - $repo = $this->createBitrix24AccountRepositoryImplementation(); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); $this->expectException(InvalidArgumentException::class); /** @phpstan-ignore-next-line */ - $repo->findOneAdminByMemberId(''); + $bitrix24AccountRepository->findOneAdminByMemberId(''); } /** @@ -180,12 +183,12 @@ public function testFindOneAdminByMemberIdWithEmptyArgs(): void #[DataProvider('bitrix24AccountForInstallDataProvider')] #[TestDox('test findOneAdminByMemberId method with happy path')] final public function testFindOneAdminByMemberIdWithHappyPath( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -193,15 +196,16 @@ final public function testFindOneAdminByMemberIdWithHappyPath( Scope $applicationScope ): void { - $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $repo = $this->createBitrix24AccountRepositoryImplementation(); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + + $bitrix24AccountRepository->save($bitrix24Account); - $repo->save($newB24Account); - $acc = $repo->getById($id); - $this->assertEquals($newB24Account, $acc); + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); - $found = $repo->findOneAdminByMemberId($memberId); + $found = $bitrix24AccountRepository->findOneAdminByMemberId($memberId); $this->assertEquals($acc, $found); } @@ -209,12 +213,12 @@ final public function testFindOneAdminByMemberIdWithHappyPath( #[DataProvider('bitrix24AccountForInstallDataProvider')] #[TestDox('test findOneAdminByMemberId method with simple user')] final public function testFindOneAdminByMemberIdWithSimpleUser( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -222,14 +226,15 @@ final public function testFindOneAdminByMemberIdWithSimpleUser( Scope $applicationScope ): void { - $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, false, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $repo = $this->createBitrix24AccountRepositoryImplementation(); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, false, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + + $bitrix24AccountRepository->save($bitrix24Account); - $repo->save($newB24Account); - $acc = $repo->getById($id); - $this->assertEquals($newB24Account, $acc); + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); - $found = $repo->findOneAdminByMemberId($memberId); + $found = $bitrix24AccountRepository->findOneAdminByMemberId($memberId); $this->assertNull($found); } @@ -237,12 +242,12 @@ final public function testFindOneAdminByMemberIdWithSimpleUser( #[DataProvider('bitrix24AccountForInstallDataProvider')] #[TestDox('test findByMemberId method with happy path')] final public function testFindByMemberIdWithHappyPath( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -250,23 +255,24 @@ final public function testFindByMemberIdWithHappyPath( Scope $applicationScope ): void { - $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $repo = $this->createBitrix24AccountRepositoryImplementation(); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); - $repo->save($newB24Account); - $acc = $repo->getById($id); - $this->assertEquals($newB24Account, $acc); + $bitrix24AccountRepository->save($bitrix24Account); - $found = $repo->findByMemberId($memberId); - $this->assertEquals($newB24Account, $found[0]); + $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 { - $repo = $this->createBitrix24AccountRepositoryImplementation(); - $found = $repo->findByMemberId('member_id'); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + $found = $bitrix24AccountRepository->findByMemberId('member_id'); $this->assertEquals([], $found); } @@ -274,10 +280,10 @@ final public function testFindByMemberIdWithHappyPathNotFound(): void #[TestDox('test findByMemberId method with empty member id')] final public function testFindByMemberIdWithEmptyMemberId(): void { - $repo = $this->createBitrix24AccountRepositoryImplementation(); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); $this->expectException(InvalidArgumentException::class); /** @phpstan-ignore-next-line */ - $repo->findByMemberId(''); + $bitrix24AccountRepository->findByMemberId(''); } /** @@ -288,12 +294,12 @@ final public function testFindByMemberIdWithEmptyMemberId(): void #[DataProvider('bitrix24AccountForInstallDataProvider')] #[TestDox('test findByMemberId method with blocked account happy path')] final public function testFindByMemberIdWithBlockedAccountHappyPath( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -301,16 +307,17 @@ final public function testFindByMemberIdWithBlockedAccountHappyPath( Scope $applicationScope ): void { - $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $repo = $this->createBitrix24AccountRepositoryImplementation(); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); - $repo->save($newB24Account); - $acc = $repo->getById($id); - $this->assertEquals($newB24Account, $acc); + $bitrix24AccountRepository->save($bitrix24Account); + + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); $acc->markAsBlocked('block by admin'); - $repo->save($acc); + $bitrix24AccountRepository->save($acc); - $found = $repo->findByMemberId($memberId, Bitrix24AccountStatus::blocked); + $found = $bitrix24AccountRepository->findByMemberId($memberId, Bitrix24AccountStatus::blocked); $this->assertEquals($acc, $found[0]); } @@ -321,12 +328,12 @@ final public function testFindByMemberIdWithBlockedAccountHappyPath( #[DataProvider('bitrix24AccountForInstallDataProvider')] #[TestDox('test findByMemberId method with account status but account not found')] final public function testFindByMemberIdWithAccountStatusAccountNotFound( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -334,14 +341,15 @@ final public function testFindByMemberIdWithAccountStatusAccountNotFound( Scope $applicationScope ): void { - $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $repo = $this->createBitrix24AccountRepositoryImplementation(); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); - $repo->save($newB24Account); - $acc = $repo->getById($id); - $this->assertEquals($newB24Account, $acc); + $bitrix24AccountRepository->save($bitrix24Account); - $found = $repo->findByMemberId($memberId, Bitrix24AccountStatus::blocked); + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); + + $found = $bitrix24AccountRepository->findByMemberId($memberId, Bitrix24AccountStatus::blocked); $this->assertEquals([], $found); } @@ -353,12 +361,12 @@ final public function testFindByMemberIdWithAccountStatusAccountNotFound( #[DataProvider('bitrix24AccountForInstallDataProvider')] #[TestDox('test findByMemberId method with is admin happy path')] final public function testFindByMemberIdWithIsAdminHappyPath( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -366,14 +374,15 @@ final public function testFindByMemberIdWithIsAdminHappyPath( Scope $applicationScope ): void { - $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $repo = $this->createBitrix24AccountRepositoryImplementation(); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); - $repo->save($newB24Account); - $acc = $repo->getById($id); - $this->assertEquals($newB24Account, $acc); + $bitrix24AccountRepository->save($bitrix24Account); - $found = $repo->findByMemberId($memberId, null, true); + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); + + $found = $bitrix24AccountRepository->findByMemberId($memberId, null, true); $this->assertEquals($acc, $found[0]); } @@ -384,12 +393,12 @@ final public function testFindByMemberIdWithIsAdminHappyPath( #[DataProvider('bitrix24AccountForInstallDataProvider')] #[TestDox('test findByMemberId method with is admin - not found')] final public function testFindByMemberIdWithIsAdminNotFound( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -397,14 +406,15 @@ final public function testFindByMemberIdWithIsAdminNotFound( Scope $applicationScope ): void { - $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, false, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $repo = $this->createBitrix24AccountRepositoryImplementation(); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, false, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + + $bitrix24AccountRepository->save($bitrix24Account); - $repo->save($newB24Account); - $acc = $repo->getById($id); - $this->assertEquals($newB24Account, $acc); + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); - $found = $repo->findByMemberId($memberId, null, true); + $found = $bitrix24AccountRepository->findByMemberId($memberId, null, true); $this->assertEquals([], $found); } @@ -415,12 +425,12 @@ final public function testFindByMemberIdWithIsAdminNotFound( #[DataProvider('bitrix24AccountForInstallDataProvider')] #[TestDox('test findByMemberId method with all args')] final public function testFindByMemberIdWithAllArgs( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -428,14 +438,15 @@ final public function testFindByMemberIdWithAllArgs( Scope $applicationScope ): void { - $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, false, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $repo = $this->createBitrix24AccountRepositoryImplementation(); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, false, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + + $bitrix24AccountRepository->save($bitrix24Account); - $repo->save($newB24Account); - $acc = $repo->getById($id); - $this->assertEquals($newB24Account, $acc); + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); - $found = $repo->findByMemberId($memberId, Bitrix24AccountStatus::new, false); + $found = $bitrix24AccountRepository->findByMemberId($memberId, Bitrix24AccountStatus::new, false); $this->assertEquals($acc, $found[0]); } @@ -446,12 +457,12 @@ final public function testFindByMemberIdWithAllArgs( #[DataProvider('bitrix24AccountForInstallDataProvider')] #[TestDox('test findByDomain method with happy path')] final public function testFindByDomainWithHappyPath( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -459,23 +470,24 @@ final public function testFindByDomainWithHappyPath( Scope $applicationScope ): void { - $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $repo = $this->createBitrix24AccountRepositoryImplementation(); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + + $bitrix24AccountRepository->save($bitrix24Account); - $repo->save($newB24Account); - $acc = $repo->getById($id); - $this->assertEquals($newB24Account, $acc); + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); - $found = $repo->findByDomain($domainUrl); - $this->assertEquals($newB24Account, $found[0]); + $found = $bitrix24AccountRepository->findByDomain($domainUrl); + $this->assertEquals($bitrix24Account, $found[0]); } #[Test] #[TestDox('test findByDomain method with happy path - not found')] final public function testFindByDomainWithHappyPathNotFound(): void { - $repo = $this->createBitrix24AccountRepositoryImplementation(); - $found = $repo->findByDomain('test.com'); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + $found = $bitrix24AccountRepository->findByDomain('test.com'); $this->assertEquals([], $found); } @@ -483,10 +495,10 @@ final public function testFindByDomainWithHappyPathNotFound(): void #[TestDox('test findByDomain method with empty domain url')] final public function testFindByDomainWithEmptyDomainUrl(): void { - $repo = $this->createBitrix24AccountRepositoryImplementation(); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); $this->expectException(InvalidArgumentException::class); /** @phpstan-ignore-next-line */ - $repo->findByDomain(''); + $bitrix24AccountRepository->findByDomain(''); } /** @@ -497,12 +509,12 @@ final public function testFindByDomainWithEmptyDomainUrl(): void #[DataProvider('bitrix24AccountForInstallDataProvider')] #[TestDox('test findByDomain method with blocked account happy path')] final public function testFindByDomainWithBlockedAccountHappyPath( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -510,16 +522,17 @@ final public function testFindByDomainWithBlockedAccountHappyPath( Scope $applicationScope ): void { - $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $repo = $this->createBitrix24AccountRepositoryImplementation(); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + + $bitrix24AccountRepository->save($bitrix24Account); - $repo->save($newB24Account); - $acc = $repo->getById($id); - $this->assertEquals($newB24Account, $acc); + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); $acc->markAsBlocked('block by admin'); - $repo->save($acc); + $bitrix24AccountRepository->save($acc); - $found = $repo->findByDomain($domainUrl, Bitrix24AccountStatus::blocked); + $found = $bitrix24AccountRepository->findByDomain($domainUrl, Bitrix24AccountStatus::blocked); $this->assertEquals($acc, $found[0]); } @@ -530,12 +543,12 @@ final public function testFindByDomainWithBlockedAccountHappyPath( #[DataProvider('bitrix24AccountForInstallDataProvider')] #[TestDox('test findByDomain method with account status but account not found')] final public function testFindByDomainWithAccountStatusAccountNotFound( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -543,14 +556,15 @@ final public function testFindByDomainWithAccountStatusAccountNotFound( Scope $applicationScope ): void { - $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $repo = $this->createBitrix24AccountRepositoryImplementation(); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + + $bitrix24AccountRepository->save($bitrix24Account); - $repo->save($newB24Account); - $acc = $repo->getById($id); - $this->assertEquals($newB24Account, $acc); + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); - $found = $repo->findByDomain($domainUrl, Bitrix24AccountStatus::blocked); + $found = $bitrix24AccountRepository->findByDomain($domainUrl, Bitrix24AccountStatus::blocked); $this->assertEquals([], $found); } @@ -562,12 +576,12 @@ final public function testFindByDomainWithAccountStatusAccountNotFound( #[DataProvider('bitrix24AccountForInstallDataProvider')] #[TestDox('test findByDomain method with is admin happy path')] final public function testFindByDomainWithIsAdminHappyPath( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -575,14 +589,15 @@ final public function testFindByDomainWithIsAdminHappyPath( Scope $applicationScope ): void { - $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $repo = $this->createBitrix24AccountRepositoryImplementation(); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, $isBitrix24UserAdmin, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + + $bitrix24AccountRepository->save($bitrix24Account); - $repo->save($newB24Account); - $acc = $repo->getById($id); - $this->assertEquals($newB24Account, $acc); + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); - $found = $repo->findByDomain($domainUrl, null, true); + $found = $bitrix24AccountRepository->findByDomain($domainUrl, null, true); $this->assertEquals($acc, $found[0]); } @@ -593,12 +608,12 @@ final public function testFindByDomainWithIsAdminHappyPath( #[DataProvider('bitrix24AccountForInstallDataProvider')] #[TestDox('test findByDomain method with is admin - not found')] final public function testFindByDomainWithIsAdminNotFound( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -606,14 +621,15 @@ final public function testFindByDomainWithIsAdminNotFound( Scope $applicationScope ): void { - $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, false, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $repo = $this->createBitrix24AccountRepositoryImplementation(); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, false, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + + $bitrix24AccountRepository->save($bitrix24Account); - $repo->save($newB24Account); - $acc = $repo->getById($id); - $this->assertEquals($newB24Account, $acc); + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); - $found = $repo->findByDomain($memberId, null, true); + $found = $bitrix24AccountRepository->findByDomain($memberId, null, true); $this->assertEquals([], $found); } @@ -624,12 +640,12 @@ final public function testFindByDomainWithIsAdminNotFound( #[DataProvider('bitrix24AccountForInstallDataProvider')] #[TestDox('test findByDomain method with all args')] final public function testFindByDomainWithAllArgs( - Uuid $id, + Uuid $uuid, int $bitrix24UserId, bool $isBitrix24UserAdmin, string $memberId, string $domainUrl, - Bitrix24AccountStatus $accountStatus, + Bitrix24AccountStatus $bitrix24AccountStatus, AuthToken $authToken, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, @@ -637,14 +653,15 @@ final public function testFindByDomainWithAllArgs( Scope $applicationScope ): void { - $newB24Account = $this->createBitrix24AccountImplementation($id, $bitrix24UserId, false, $memberId, $domainUrl, $accountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); - $repo = $this->createBitrix24AccountRepositoryImplementation(); + $bitrix24Account = $this->createBitrix24AccountImplementation($uuid, $bitrix24UserId, false, $memberId, $domainUrl, $bitrix24AccountStatus, $authToken, $createdAt, $updatedAt, $applicationVersion, $applicationScope); + $bitrix24AccountRepository = $this->createBitrix24AccountRepositoryImplementation(); + + $bitrix24AccountRepository->save($bitrix24Account); - $repo->save($newB24Account); - $acc = $repo->getById($id); - $this->assertEquals($newB24Account, $acc); + $acc = $bitrix24AccountRepository->getById($uuid); + $this->assertEquals($bitrix24Account, $acc); - $found = $repo->findByDomain($domainUrl, Bitrix24AccountStatus::new, false); + $found = $bitrix24AccountRepository->findByDomain($domainUrl, Bitrix24AccountStatus::new, false); $this->assertEquals($acc, $found[0]); } diff --git a/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementation.php b/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementation.php index f13fe25a..eb790fa0 100644 --- a/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementation.php +++ b/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementation.php @@ -37,13 +37,14 @@ public function delete(Uuid $uuid): void { $this->logger->debug('b24AccountRepository.delete', ['id' => $uuid->toRfc4122()]); - $item = $this->getById($uuid); - if (Bitrix24AccountStatus::deleted !== $item->getStatus()) { + $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»', - $item->getId()->toRfc4122(), - $item->getStatus()->name + $bitrix24Account->getId()->toRfc4122(), + $bitrix24Account->getStatus()->name )); } + unset($this->items[$uuid->toRfc4122()]); } @@ -54,6 +55,7 @@ public function getById(Uuid $uuid): Bitrix24AccountInterface 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()]; } @@ -80,11 +82,11 @@ public function findOneAdminByMemberId(string $memberId): ?Bitrix24AccountInterf /** * @throws InvalidArgumentException */ - public function findByMemberId(string $memberId, ?Bitrix24AccountStatus $status = null, ?bool $isAdmin = null): array + public function findByMemberId(string $memberId, ?Bitrix24AccountStatus $bitrix24AccountStatus = null, ?bool $isAdmin = null): array { $this->logger->debug('b24AccountRepository.findByMemberId', [ 'memberId' => $memberId, - 'status' => $status?->name, + 'status' => $bitrix24AccountStatus?->name, 'isAdmin' => $isAdmin ]); @@ -98,7 +100,7 @@ public function findByMemberId(string $memberId, ?Bitrix24AccountStatus $status continue; } - $isStatusMatch = ($status === null || $status === $item->getStatus()); + $isStatusMatch = (!$bitrix24AccountStatus instanceof Bitrix24AccountStatus || $bitrix24AccountStatus === $item->getStatus()); $isAdminMatch = ($isAdmin === null || $isAdmin === $item->isBitrix24UserAdmin()); if ($isStatusMatch && $isAdminMatch) { @@ -106,17 +108,18 @@ public function findByMemberId(string $memberId, ?Bitrix24AccountStatus $status } } + return $items; } /** * @throws InvalidArgumentException */ - public function findByDomain(string $domainUrl, ?Bitrix24AccountStatus $status = null, ?bool $isAdmin = null): array + public function findByDomain(string $domainUrl, ?Bitrix24AccountStatus $bitrix24AccountStatus = null, ?bool $isAdmin = null): array { $this->logger->debug('b24AccountRepository.findByDomain', [ 'domain' => $domainUrl, - 'status' => $status?->name, + 'status' => $bitrix24AccountStatus?->name, 'isAdmin' => $isAdmin ]); @@ -130,7 +133,7 @@ public function findByDomain(string $domainUrl, ?Bitrix24AccountStatus $status = continue; } - $isStatusMatch = ($status === null || $status === $item->getStatus()); + $isStatusMatch = (!$bitrix24AccountStatus instanceof Bitrix24AccountStatus || $bitrix24AccountStatus === $item->getStatus()); $isAdminMatch = ($isAdmin === null || $isAdmin === $item->isBitrix24UserAdmin()); if ($isStatusMatch && $isAdminMatch) { @@ -138,6 +141,7 @@ public function findByDomain(string $domainUrl, ?Bitrix24AccountStatus $status = } } + return $items; } } \ 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 index e8079635..08602f43 100644 --- a/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceReferenceImplementationTest.php +++ b/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceReferenceImplementationTest.php @@ -26,7 +26,7 @@ protected function createContactPersonImplementation( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -45,7 +45,7 @@ protected function createContactPersonImplementation( $email, $emailVerifiedAt, $comment, - $mobilePhone, + $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, diff --git a/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceTest.php b/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceTest.php index 07b3536e..46f4f519 100644 --- a/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceTest.php +++ b/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceTest.php @@ -34,7 +34,7 @@ abstract protected function createContactPersonImplementation( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -46,7 +46,7 @@ abstract protected function createContactPersonImplementation( #[DataProvider('contactPersonDataProvider')] #[TestDox('test getId method')] final public function testGetId( - Uuid $id, + Uuid $uuid, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, ContactPersonStatus $contactPersonStatus, @@ -56,7 +56,7 @@ final public function testGetId( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -64,15 +64,15 @@ final public function testGetId( ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); - $this->assertEquals($id, $contactPerson->getId()); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($uuid, $contactPerson->getId()); } #[Test] #[DataProvider('contactPersonDataProvider')] #[TestDox('test getStatus method')] final public function testGetStatus( - Uuid $id, + Uuid $uuid, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, ContactPersonStatus $contactPersonStatus, @@ -82,7 +82,7 @@ final public function testGetStatus( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -90,7 +90,7 @@ final public function testGetStatus( ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); $this->assertEquals($contactPersonStatus, $contactPerson->getStatus()); } @@ -98,7 +98,7 @@ final public function testGetStatus( #[DataProvider('contactPersonDataProvider')] #[TestDox('test markAsActive method')] final public function testMarkAsActive( - Uuid $id, + Uuid $uuid, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, ContactPersonStatus $contactPersonStatus, @@ -108,7 +108,7 @@ final public function testMarkAsActive( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -116,7 +116,7 @@ final public function testMarkAsActive( ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); $contactPerson->markAsBlocked('block contact person'); $this->assertEquals(ContactPersonStatus::blocked, $contactPerson->getStatus()); $message = 'unblock contact person'; @@ -129,7 +129,7 @@ final public function testMarkAsActive( #[DataProvider('contactPersonDataProvider')] #[TestDox('test markAsBlocked method')] final public function testMarkAsBlocked( - Uuid $id, + Uuid $uuid, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, ContactPersonStatus $contactPersonStatus, @@ -139,7 +139,7 @@ final public function testMarkAsBlocked( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -147,7 +147,7 @@ final public function testMarkAsBlocked( ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); $message = 'block contact person'; $contactPerson->markAsBlocked($message); $this->assertEquals(ContactPersonStatus::blocked, $contactPerson->getStatus()); @@ -158,7 +158,7 @@ final public function testMarkAsBlocked( #[DataProvider('contactPersonDataProvider')] #[TestDox('test markAsDeleted method')] final public function testMarkAsDeleted( - Uuid $id, + Uuid $uuid, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, ContactPersonStatus $contactPersonStatus, @@ -168,7 +168,7 @@ final public function testMarkAsDeleted( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -176,7 +176,7 @@ final public function testMarkAsDeleted( ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); $message = 'soft delete contact person'; $contactPerson->markAsDeleted($message); $this->assertEquals(ContactPersonStatus::deleted, $contactPerson->getStatus()); @@ -187,7 +187,7 @@ final public function testMarkAsDeleted( #[DataProvider('contactPersonDataProvider')] #[TestDox('test markAsDeleted method for blocked account')] final public function testMarkAsDeletedBlockedAccount( - Uuid $id, + Uuid $uuid, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, ContactPersonStatus $contactPersonStatus, @@ -197,7 +197,7 @@ final public function testMarkAsDeletedBlockedAccount( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -205,7 +205,7 @@ final public function testMarkAsDeletedBlockedAccount( ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); $message = 'block contact person'; $contactPerson->markAsBlocked($message); $this->assertEquals(ContactPersonStatus::blocked, $contactPerson->getStatus()); @@ -220,7 +220,7 @@ final public function testMarkAsDeletedBlockedAccount( #[DataProvider('contactPersonDataProvider')] #[TestDox('test markAsDeleted method')] final public function testMarkAsDeletedDeletedAccount( - Uuid $id, + Uuid $uuid, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, ContactPersonStatus $contactPersonStatus, @@ -230,7 +230,7 @@ final public function testMarkAsDeletedDeletedAccount( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -238,7 +238,7 @@ final public function testMarkAsDeletedDeletedAccount( ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); $message = 'soft delete contact person'; $contactPerson->markAsDeleted($message); $this->expectException(InvalidArgumentException::class); @@ -249,7 +249,7 @@ final public function testMarkAsDeletedDeletedAccount( #[DataProvider('contactPersonDataProvider')] #[TestDox('test getFullName method')] final public function testGetFullName( - Uuid $id, + Uuid $uuid, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, ContactPersonStatus $contactPersonStatus, @@ -259,7 +259,7 @@ final public function testGetFullName( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -267,7 +267,7 @@ final public function testGetFullName( ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); $this->assertEquals(new FullName($name, $surname, $patronymic), $contactPerson->getFullName()); } @@ -275,7 +275,7 @@ final public function testGetFullName( #[DataProvider('contactPersonDataProvider')] #[TestDox('test changeFullName method')] final public function testChangeFullName( - Uuid $id, + Uuid $uuid, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, ContactPersonStatus $contactPersonStatus, @@ -285,7 +285,7 @@ final public function testChangeFullName( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -293,7 +293,7 @@ final public function testChangeFullName( ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); $newFullName = DemoDataGenerator::getFullName(); $contactPerson->changeFullName($newFullName); $this->assertEquals($newFullName, $contactPerson->getFullName()); @@ -303,7 +303,7 @@ final public function testChangeFullName( #[DataProvider('contactPersonDataProvider')] #[TestDox('test getUpdatedAt method')] final public function testGetUpdatedAt( - Uuid $id, + Uuid $uuid, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, ContactPersonStatus $contactPersonStatus, @@ -313,7 +313,7 @@ final public function testGetUpdatedAt( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -321,7 +321,7 @@ final public function testGetUpdatedAt( ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); $contactPerson->markAsBlocked('test block'); $this->assertEquals($createdAt, $contactPerson->getCreatedAt()); $this->assertNotEquals($updatedAt, $contactPerson->getUpdatedAt()); @@ -331,7 +331,7 @@ final public function testGetUpdatedAt( #[DataProvider('contactPersonDataProvider')] #[TestDox('test getCreatedAt method')] final public function testCreatedAt( - Uuid $id, + Uuid $uuid, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, ContactPersonStatus $contactPersonStatus, @@ -341,7 +341,7 @@ final public function testCreatedAt( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -349,7 +349,7 @@ final public function testCreatedAt( ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); $this->assertEquals($createdAt, $contactPerson->getCreatedAt()); } @@ -357,7 +357,7 @@ final public function testCreatedAt( #[DataProvider('contactPersonDataProvider')] #[TestDox('test getEmail method')] final public function testGetEmail( - Uuid $id, + Uuid $uuid, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, ContactPersonStatus $contactPersonStatus, @@ -367,7 +367,7 @@ final public function testGetEmail( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -375,7 +375,7 @@ final public function testGetEmail( ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); $this->assertEquals($email, $contactPerson->getEmail()); } @@ -383,7 +383,7 @@ final public function testGetEmail( #[DataProvider('contactPersonDataProvider')] #[TestDox('test changeEmail method')] final public function testChangeEmail( - Uuid $id, + Uuid $uuid, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, ContactPersonStatus $contactPersonStatus, @@ -393,7 +393,7 @@ final public function testChangeEmail( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -401,7 +401,7 @@ final public function testChangeEmail( ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); $newEmail = DemoDataGenerator::getEmail(); $contactPerson->changeEmail($newEmail); @@ -427,7 +427,7 @@ final public function testChangeEmail( #[DataProvider('contactPersonDataProvider')] #[TestDox('test markEmailAsVerified method')] final public function testMarkEmailAsVerified( - Uuid $id, + Uuid $uuid, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, ContactPersonStatus $contactPersonStatus, @@ -437,7 +437,7 @@ final public function testMarkEmailAsVerified( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -445,7 +445,7 @@ final public function testMarkEmailAsVerified( ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); $newEmail = DemoDataGenerator::getEmail(); // email not verified @@ -460,7 +460,7 @@ final public function testMarkEmailAsVerified( #[DataProvider('contactPersonDataProvider')] #[TestDox('test getMobilePhone method')] final public function testGetMobilePhone( - Uuid $id, + Uuid $uuid, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, ContactPersonStatus $contactPersonStatus, @@ -470,7 +470,7 @@ final public function testGetMobilePhone( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -478,15 +478,15 @@ final public function testGetMobilePhone( ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); - $this->assertEquals($mobilePhone, $contactPerson->getMobilePhone()); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($phoneNumber, $contactPerson->getMobilePhone()); } #[Test] #[DataProvider('contactPersonDataProvider')] #[TestDox('test changeMobilePhone method')] final public function testChangeMobilePhone( - Uuid $id, + Uuid $uuid, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, ContactPersonStatus $contactPersonStatus, @@ -496,7 +496,7 @@ final public function testChangeMobilePhone( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -504,7 +504,7 @@ final public function testChangeMobilePhone( ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); $phone = DemoDataGenerator::getMobilePhone(); $contactPerson->changeMobilePhone($phone); @@ -523,7 +523,7 @@ final public function testChangeMobilePhone( #[DataProvider('contactPersonDataProvider')] #[TestDox('test getMobilePhoneVerifiedAt method')] final public function testGetMobilePhoneVerifiedAt( - Uuid $id, + Uuid $uuid, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, ContactPersonStatus $contactPersonStatus, @@ -533,7 +533,7 @@ final public function testGetMobilePhoneVerifiedAt( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -541,8 +541,8 @@ final public function testGetMobilePhoneVerifiedAt( ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); - $this->assertEquals($mobilePhone, $contactPerson->getMobilePhone()); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($phoneNumber, $contactPerson->getMobilePhone()); $phone = DemoDataGenerator::getMobilePhone(); $contactPerson->changeMobilePhone($phone, true); @@ -553,7 +553,7 @@ final public function testGetMobilePhoneVerifiedAt( #[DataProvider('contactPersonDataProvider')] #[TestDox('test markMobilePhoneAsVerified method')] final public function testMarkMobilePhoneAsVerified( - Uuid $id, + Uuid $uuid, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, ContactPersonStatus $contactPersonStatus, @@ -563,7 +563,7 @@ final public function testMarkMobilePhoneAsVerified( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -571,8 +571,8 @@ final public function testMarkMobilePhoneAsVerified( ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); - $this->assertEquals($mobilePhone, $contactPerson->getMobilePhone()); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($phoneNumber, $contactPerson->getMobilePhone()); $phone = DemoDataGenerator::getMobilePhone(); $contactPerson->changeMobilePhone($phone); @@ -585,7 +585,7 @@ final public function testMarkMobilePhoneAsVerified( #[DataProvider('contactPersonDataProvider')] #[TestDox('test getComment method')] final public function testGetComment( - Uuid $id, + Uuid $uuid, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, ContactPersonStatus $contactPersonStatus, @@ -595,7 +595,7 @@ final public function testGetComment( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -603,7 +603,7 @@ final public function testGetComment( ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); $comment = 'block reason'; $contactPerson->markAsBlocked($comment); $this->assertEquals($comment, $contactPerson->getComment()); @@ -613,7 +613,7 @@ final public function testGetComment( #[DataProvider('contactPersonDataProvider')] #[TestDox('test setExternalId method')] final public function testSetExternalId( - Uuid $id, + Uuid $uuid, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, ContactPersonStatus $contactPersonStatus, @@ -623,7 +623,7 @@ final public function testSetExternalId( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -631,18 +631,18 @@ final public function testSetExternalId( ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); - $uuid = Uuid::v7(); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $uuidV7 = Uuid::v7(); - $contactPerson->setExternalId($uuid->toRfc4122()); - $this->assertEquals($uuid->toRfc4122(), $contactPerson->getExternalId()); + $contactPerson->setExternalId($uuidV7->toRfc4122()); + $this->assertEquals($uuidV7->toRfc4122(), $contactPerson->getExternalId()); } #[Test] #[DataProvider('contactPersonDataProvider')] #[TestDox('test getExternalId method')] final public function testGetExternalId( - Uuid $id, + Uuid $uuid, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, ContactPersonStatus $contactPersonStatus, @@ -652,7 +652,7 @@ final public function testGetExternalId( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -661,12 +661,12 @@ final public function testGetExternalId( ): void { $externalId = null; - $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); $this->assertNull($contactPerson->getExternalId()); - $uuid = Uuid::v7(); - $externalId = $uuid->toRfc4122(); - $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $uuidV7 = Uuid::v7(); + $externalId = $uuidV7->toRfc4122(); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); $this->assertEquals($externalId, $contactPerson->getExternalId()); } @@ -674,7 +674,7 @@ final public function testGetExternalId( #[DataProvider('contactPersonDataProvider')] #[TestDox('test getUserAgent method')] final public function testGetUserAgent( - Uuid $id, + Uuid $uuid, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, ContactPersonStatus $contactPersonStatus, @@ -684,7 +684,7 @@ final public function testGetUserAgent( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -692,7 +692,7 @@ final public function testGetUserAgent( ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); $this->assertEquals($userAgent, $contactPerson->getUserAgent()); } @@ -700,7 +700,7 @@ final public function testGetUserAgent( #[DataProvider('contactPersonDataProvider')] #[TestDox('test getUserAgentReferer method')] final public function testGetUserAgentReferer( - Uuid $id, + Uuid $uuid, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, ContactPersonStatus $contactPersonStatus, @@ -710,7 +710,7 @@ final public function testGetUserAgentReferer( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -718,7 +718,7 @@ final public function testGetUserAgentReferer( ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); $this->assertEquals($userAgentReferer, $contactPerson->getUserAgentReferer()); } @@ -726,7 +726,7 @@ final public function testGetUserAgentReferer( #[DataProvider('contactPersonDataProvider')] #[TestDox('test getUserAgentIp method')] final public function testGetUserAgentIp( - Uuid $id, + Uuid $uuid, CarbonImmutable $createdAt, CarbonImmutable $updatedAt, ContactPersonStatus $contactPersonStatus, @@ -736,7 +736,7 @@ final public function testGetUserAgentIp( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -744,7 +744,7 @@ final public function testGetUserAgentIp( ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($id, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); $this->assertEquals($userAgentIp, $contactPerson->getUserAgentIp()); } diff --git a/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonReferenceEntityImplementation.php b/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonReferenceEntityImplementation.php index 2ced7e17..33799a2a 100644 --- a/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonReferenceEntityImplementation.php +++ b/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonReferenceEntityImplementation.php @@ -119,6 +119,7 @@ public function changeEmail(?string $email, ?bool $isEmailVerified = null): void if ($isEmailVerified === true) { $this->emailVerifiedAt = new CarbonImmutable(); } + $this->updatedAt = new CarbonImmutable(); } @@ -138,13 +139,14 @@ public function markEmailAsVerified(): void $this->updatedAt = new CarbonImmutable(); } - public function changeMobilePhone(?PhoneNumber $mobilePhone, ?bool $isMobilePhoneVerified = null): void + public function changeMobilePhone(?PhoneNumber $phoneNumber, ?bool $isMobilePhoneVerified = null): void { $this->mobilePhoneVerifiedAt = null; - $this->mobilePhone = $mobilePhone; + $this->mobilePhone = $phoneNumber; if ($isMobilePhoneVerified === true) { $this->mobilePhoneVerifiedAt = new CarbonImmutable(); } + $this->updatedAt = new CarbonImmutable(); } diff --git a/tests/Unit/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php b/tests/Unit/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php index d0e32206..8954c932 100644 --- a/tests/Unit/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php +++ b/tests/Unit/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php @@ -35,7 +35,7 @@ abstract protected function createContactPersonImplementation( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -62,7 +62,7 @@ final public function testSave( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -70,11 +70,11 @@ final public function testSave( ?IP $userAgentIp ): void { - $repo = $this->createContactPersonRepositoryImplementation(); - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPersonRepository = $this->createContactPersonRepositoryImplementation(); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); - $repo->save($contactPerson); - $acc = $repo->getById($contactPerson->getId()); + $contactPersonRepository->save($contactPerson); + $acc = $contactPersonRepository->getById($contactPerson->getId()); $this->assertEquals($contactPerson, $acc); } @@ -96,7 +96,7 @@ final public function testDelete( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -104,16 +104,17 @@ final public function testDelete( ?IP $userAgentIp ): void { - $repo = $this->createContactPersonRepositoryImplementation(); - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPersonRepository = $this->createContactPersonRepositoryImplementation(); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); - $repo->save($contactPerson); - $contactPerson = $repo->getById($contactPerson->getId()); + $contactPersonRepository->save($contactPerson); + $contactPerson = $contactPersonRepository->getById($contactPerson->getId()); $contactPerson->markAsDeleted('soft delete account'); - $repo->delete($contactPerson->getId()); + + $contactPersonRepository->delete($contactPerson->getId()); $this->expectException(ContactPersonNotFoundException::class); - $repo->getById($contactPerson->getId()); + $contactPersonRepository->getById($contactPerson->getId()); } #[Test] @@ -130,7 +131,7 @@ final public function testDeleteWithUnsavedElement( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -138,11 +139,11 @@ final public function testDeleteWithUnsavedElement( ?IP $userAgentIp ): void { - $repo = $this->createContactPersonRepositoryImplementation(); - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPersonRepository = $this->createContactPersonRepositoryImplementation(); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); $this->expectException(ContactPersonNotFoundException::class); - $repo->delete($contactPerson->getId()); + $contactPersonRepository->delete($contactPerson->getId()); } #[Test] @@ -159,7 +160,7 @@ final public function testGetById( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -167,11 +168,11 @@ final public function testGetById( ?IP $userAgentIp ): void { - $repo = $this->createContactPersonRepositoryImplementation(); - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPersonRepository = $this->createContactPersonRepositoryImplementation(); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); - $repo->save($contactPerson); - $acc = $repo->getById($contactPerson->getId()); + $contactPersonRepository->save($contactPerson); + $acc = $contactPersonRepository->getById($contactPerson->getId()); $this->assertEquals($contactPerson, $acc); } @@ -189,7 +190,7 @@ final public function testGetByIdWithNonExist( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -197,10 +198,10 @@ final public function testGetByIdWithNonExist( ?IP $userAgentIp ): void { - $repo = $this->createContactPersonRepositoryImplementation(); + $contactPersonRepository = $this->createContactPersonRepositoryImplementation(); $this->expectException(ContactPersonNotFoundException::class); - $repo->getById(Uuid::v7()); + $contactPersonRepository->getById(Uuid::v7()); } #[Test] @@ -217,7 +218,7 @@ final public function testFindByEmailWithHappyPath( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -225,11 +226,11 @@ final public function testFindByEmailWithHappyPath( ?IP $userAgentIp ): void { - $repo = $this->createContactPersonRepositoryImplementation(); - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPersonRepository = $this->createContactPersonRepositoryImplementation(); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); - $repo->save($contactPerson); - $contactPersons = $repo->findByEmail($email); + $contactPersonRepository->save($contactPerson); + $contactPersons = $contactPersonRepository->findByEmail($email); $this->assertEquals($contactPerson, $contactPersons[0]); } @@ -247,7 +248,7 @@ final public function testFindByEmailWithNonExistsEmail( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -255,11 +256,11 @@ final public function testFindByEmailWithNonExistsEmail( ?IP $userAgentIp ): void { - $repo = $this->createContactPersonRepositoryImplementation(); - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPersonRepository = $this->createContactPersonRepositoryImplementation(); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); - $repo->save($contactPerson); - $contactPersons = $repo->findByEmail('this.email.doesnt.exists@b24.com'); + $contactPersonRepository->save($contactPerson); + $contactPersons = $contactPersonRepository->findByEmail('this.email.doesnt.exists@b24.com'); $this->assertEmpty($contactPersons); } @@ -277,7 +278,7 @@ final public function testFindByEmailWithDifferentStatuses( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -285,11 +286,11 @@ final public function testFindByEmailWithDifferentStatuses( ?IP $userAgentIp ): void { - $repo = $this->createContactPersonRepositoryImplementation(); - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPersonRepository = $this->createContactPersonRepositoryImplementation(); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); - $repo->save($contactPerson); - $contactPersons = $repo->findByEmail($email, $contactPersonStatus); + $contactPersonRepository->save($contactPerson); + $contactPersons = $contactPersonRepository->findByEmail($email, $contactPersonStatus); $this->assertEquals($contactPerson, $contactPersons[0]); } @@ -298,18 +299,18 @@ final public function testFindByEmailWithDifferentStatuses( #[TestDox('test find by email with verified email')] final public function testFindByEmailWithVerifiedEmail(array $items): void { - $repo = $this->createContactPersonRepositoryImplementation();$emailToFind = null; + $contactPersonRepository = $this->createContactPersonRepositoryImplementation(); $expectedContactPerson = null; foreach ($items as $item) { [$uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp] = $item; $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); - $repo->save($contactPerson); - if ($expectedContactPerson === null) { + $contactPersonRepository->save($contactPerson); + if (!$expectedContactPerson instanceof \Bitrix24\SDK\Application\Contracts\ContactPersons\Entity\ContactPersonInterface) { $expectedContactPerson = $contactPerson; } } - $result = $repo->findByEmail($expectedContactPerson->getEmail()); + $result = $contactPersonRepository->findByEmail($expectedContactPerson->getEmail()); $this->assertCount(1, $result); $this->assertEquals($expectedContactPerson, $result[0]); diff --git a/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementation.php b/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementation.php index 31a332db..2ac5f694 100644 --- a/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementation.php +++ b/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementation.php @@ -38,13 +38,14 @@ public function delete(Uuid $uuid): void { $this->logger->debug('InMemoryContactPersonRepositoryImplementation.delete', ['id' => $uuid->toRfc4122()]); - $item = $this->getById($uuid); - if (ContactPersonStatus::deleted !== $item->getStatus()) { + $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', - $item->getId()->toRfc4122(), - $item->getStatus()->name, + $contactPerson->getId()->toRfc4122(), + $contactPerson->getStatus()->name, )); } + unset($this->items[$uuid->toRfc4122()]); } @@ -58,54 +59,64 @@ public function getById(Uuid $uuid): ContactPersonInterface 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 $status = null, ?bool $isEmailVerified = null): array + public function findByEmail(string $email, ?ContactPersonStatus $contactPersonStatus = null, ?bool $isEmailVerified = null): array { $result = []; - foreach ($this->items as $contactPerson) { - if ($email !== $contactPerson->getEmail()) { + foreach ($this->items as $item) { + if ($email !== $item->getEmail()) { continue; } - if ($status !== null && $status !== $contactPerson->getStatus()) { + + if ($contactPersonStatus instanceof ContactPersonStatus && $contactPersonStatus !== $item->getStatus()) { continue; } - if ($isEmailVerified !== null && $isEmailVerified !== ($contactPerson->getEmailVerifiedAt() !== null)) { + + if ($isEmailVerified !== null && $isEmailVerified !== ($item->getEmailVerifiedAt() !== null)) { continue; } - $result[] = $contactPerson; + + $result[] = $item; } + return $result; } - public function findByPhone(PhoneNumber $phoneNumber, ?ContactPersonStatus $status = null, ?bool $isPhoneVerified = null): array + public function findByPhone(PhoneNumber $phoneNumber, ?ContactPersonStatus $contactPersonStatus = null, ?bool $isPhoneVerified = null): array { $result = []; - foreach ($this->items as $contactPerson) { - if ($phoneNumber !== $contactPerson->getMobilePhone()) { + foreach ($this->items as $item) { + if ($phoneNumber !== $item->getMobilePhone()) { continue; } - if ($status !== null && $status !== $contactPerson->getStatus()) { + + if ($contactPersonStatus instanceof ContactPersonStatus && $contactPersonStatus !== $item->getStatus()) { continue; } - if ($isPhoneVerified !== null && $isPhoneVerified !== ($contactPerson->getMobilePhoneVerifiedAt() !== null)) { + + if ($isPhoneVerified !== null && $isPhoneVerified !== ($item->getMobilePhoneVerifiedAt() !== null)) { continue; } - $result[] = $contactPerson; + + $result[] = $item; } + return $result; } public function findByExternalId(string $externalId): ?ContactPersonInterface { $result = null; - foreach ($this->items as $contactPerson) { - if ($externalId === $contactPerson->getExternalId()) { - $result = $contactPerson; + foreach ($this->items as $item) { + if ($externalId === $item->getExternalId()) { + $result = $item; break; } } + 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 index 5bf7f57f..d0e374ce 100644 --- a/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementationTest.php +++ b/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementationTest.php @@ -64,7 +64,7 @@ protected function createContactPersonImplementation( ?string $email, ?CarbonImmutable $emailVerifiedAt, ?string $comment, - ?PhoneNumber $mobilePhone, + ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?string $userAgent, @@ -83,7 +83,7 @@ protected function createContactPersonImplementation( $email, $emailVerifiedAt, $comment, - $mobilePhone, + $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, From 85a0ab7abf48b62545e0b5bd6eb188c17f8ceeb1 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 22 Jul 2024 01:50:55 +0600 Subject: [PATCH 103/138] Update ContactPersonRepository findByExternalId method The method findByExternalId within the ContactPersonRepository has been expanded to account for various scenarios. It now checks for empty ExternalId input and returns an array, instead of a single output, because a contact person can have multiple installations across different portals. Associated tests have been added or updated accordingly. Signed-off-by: mesilov --- .../ContactPersonRepositoryInterface.php | 6 +- .../ContactPersonRepositoryInterfaceTest.php | 165 +++++++++++++++++- ...yContactPersonRepositoryImplementation.php | 15 +- 3 files changed, 176 insertions(+), 10 deletions(-) diff --git a/src/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterface.php b/src/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterface.php index 0a38fd97..0042e73e 100644 --- a/src/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterface.php +++ b/src/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterface.php @@ -48,7 +48,11 @@ public function findByPhone(PhoneNumber $phoneNumber, ?ContactPersonStatus $cont /** * 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): ?ContactPersonInterface; + public function findByExternalId(string $externalId, ?ContactPersonStatus $contactPersonStatus = null): array; } \ No newline at end of file diff --git a/tests/Unit/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php b/tests/Unit/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php index 8954c932..dfb1d82c 100644 --- a/tests/Unit/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php +++ b/tests/Unit/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php @@ -117,6 +117,9 @@ final public function testDelete( $contactPersonRepository->getById($contactPerson->getId()); } + /** + * @throws InvalidArgumentException + */ #[Test] #[DataProvider('contactPersonDataProvider')] #[TestDox('test delete method with unsaved element')] @@ -146,6 +149,9 @@ final public function testDeleteWithUnsavedElement( $contactPersonRepository->delete($contactPerson->getId()); } + /** + * @throws ContactPersonNotFoundException + */ #[Test] #[DataProvider('contactPersonDataProvider')] #[TestDox('test getById method with happy path')] @@ -305,21 +311,170 @@ final public function testFindByEmailWithVerifiedEmail(array $items): void [$uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp] = $item; $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); $contactPersonRepository->save($contactPerson); - if (!$expectedContactPerson instanceof \Bitrix24\SDK\Application\Contracts\ContactPersons\Entity\ContactPersonInterface) { + if (!$expectedContactPerson instanceof ContactPersonInterface) { $expectedContactPerson = $contactPerson; } } - $result = $contactPersonRepository->findByEmail($expectedContactPerson->getEmail()); + $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, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp] = $item; + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $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, + ?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, $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, + ?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, $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, + ?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, $userAgent, $userAgentReferer, $userAgentIp); + + $contactPersonRepository->save($contactPerson); + $this->expectException(InvalidArgumentException::class); + $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, $userAgent, $userAgentReferer, $userAgentIp] = $item; + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $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' => [ [ @@ -353,8 +508,8 @@ public static function contactPersonManyAccountsDataProvider(): Generator null, 'comment', DemoDataGenerator::getMobilePhone(), - CarbonImmutable::now(), null, + $externalId, DemoDataGenerator::getUserAgent(), 'https://bitrix24.com/apps/store?utm_source=bx24', DemoDataGenerator::getUserAgentIp() @@ -371,8 +526,8 @@ public static function contactPersonManyAccountsDataProvider(): Generator null, 'comment', DemoDataGenerator::getMobilePhone(), - CarbonImmutable::now(), null, + $externalId, DemoDataGenerator::getUserAgent(), 'https://bitrix24.com/apps/store?utm_source=bx24', DemoDataGenerator::getUserAgentIp() diff --git a/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementation.php b/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementation.php index 2ac5f694..43a5b79f 100644 --- a/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementation.php +++ b/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementation.php @@ -107,13 +107,20 @@ public function findByPhone(PhoneNumber $phoneNumber, ?ContactPersonStatus $cont return $result; } - public function findByExternalId(string $externalId): ?ContactPersonInterface + public function findByExternalId(string $externalId, ?ContactPersonStatus $contactPersonStatus = null): array { - $result = null; + $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; - break; + $result[] = $item; } } From c8631b511e37be99e199ef1ba0cdb7a8a92a5289 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 22 Jul 2024 01:51:53 +0600 Subject: [PATCH 104/138] Update variable names for clarity Updated variable names in various telephony test files for a better understanding of the return value being reflected. The new names specifically indicate the action taken and the result received, making the purpose of each test step clearer. This change upholds the quality of the codebase by promoting readability and maintainability. Signed-off-by: mesilov --- .../Telephony/Call/Service/CallTest.php | 8 ++-- .../ExternalCall/Service/ExternalCallTest.php | 14 +++---- .../ExternalLine/Service/ExternalLineTest.php | 8 ++-- .../Voximplant/Line/Service/LineTest.php | 6 +-- .../Telephony/Voximplant/Sip/SipTest.php | 40 +++++++++---------- 5 files changed, 38 insertions(+), 38 deletions(-) diff --git a/tests/Integration/Services/Telephony/Call/Service/CallTest.php b/tests/Integration/Services/Telephony/Call/Service/CallTest.php index d8d21038..51ebcac9 100644 --- a/tests/Integration/Services/Telephony/Call/Service/CallTest.php +++ b/tests/Integration/Services/Telephony/Call/Service/CallTest.php @@ -55,7 +55,7 @@ public static function callIdDataProvider(): Generator 'UF_PHONE_INNER' => $innerPhoneNumber ] ); - $res = $externalCall->register( + $externalCallRegisteredResult = $externalCall->register( $innerPhoneNumber, $currentB24UserId, $phoneNumber, @@ -70,7 +70,7 @@ public static function callIdDataProvider(): Generator ); yield 'default callId' => [ - $res->getExternalCallRegistered()->CALL_ID, + $externalCallRegisteredResult->getExternalCallRegistered()->CALL_ID, $currentB24UserId ]; } @@ -102,7 +102,7 @@ public function testFinishWithUserId(string $callId, int $currentB24UserId): voi $filename ); - $res = $this->call->attachTranscription( + $transcriptAttachedResult = $this->call->attachTranscription( $callId, $money, [ @@ -121,7 +121,7 @@ public function testFinishWithUserId(string $callId, int $currentB24UserId): voi ] ); - $this->assertGreaterThan(0, $res->getTranscriptAttachItem()->TRANSCRIPT_ID); + $this->assertGreaterThan(0, $transcriptAttachedResult->getTranscriptAttachItem()->TRANSCRIPT_ID); } protected function setUp(): void diff --git a/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php b/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php index d8369eec..a25f0cf7 100644 --- a/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php +++ b/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php @@ -53,7 +53,7 @@ public static function callIdDataProvider(): Generator 'UF_PHONE_INNER' => $innerPhoneNumber ] ); - $res = $externalCall->register( + $externalCallRegisteredResult = $externalCall->register( $innerPhoneNumber, $currentB24UserId, $phoneNumber, @@ -68,7 +68,7 @@ public static function callIdDataProvider(): Generator ); yield 'default callId' => [ - $res->getExternalCallRegistered()->CALL_ID, + $externalCallRegisteredResult->getExternalCallRegistered()->CALL_ID, $currentB24UserId ]; } @@ -94,7 +94,7 @@ public function testRegister(): void ] ); - $res = $this->externalCall->register( + $externalCallRegisteredResult = $this->externalCall->register( $innerPhoneNumber, $currentB24UserId, $phoneNumber, @@ -108,7 +108,7 @@ public function testRegister(): void ); - $this->assertNotEmpty($res->getExternalCallRegistered()->CALL_ID); + $this->assertNotEmpty($externalCallRegisteredResult->getExternalCallRegistered()->CALL_ID); } /** @@ -143,7 +143,7 @@ public function testFinishWithUserId(string $callId, int $currentB24UserId): voi $money = new Money(10000, new Currency('USD')); $duration = 100; - $fr = $this->externalCall->finishForUserId( + $externalCallFinishedResult = $this->externalCall->finishForUserId( $callId, $currentB24UserId, $duration, @@ -152,8 +152,8 @@ public function testFinishWithUserId(string $callId, int $currentB24UserId): voi true ); - $this->assertTrue($fr->getExternalCallFinished()->COST->equals($money)); - $this->assertEquals($fr->getExternalCallFinished()->CALL_DURATION, $duration); + $this->assertTrue($externalCallFinishedResult->getExternalCallFinished()->COST->equals($money)); + $this->assertEquals($externalCallFinishedResult->getExternalCallFinished()->CALL_DURATION, $duration); } diff --git a/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php b/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php index 8c4fc6af..113c2171 100644 --- a/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php +++ b/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php @@ -30,8 +30,8 @@ class ExternalLineTest extends TestCase public function testExternalLineAdd(): void { $lineNumber = time() . abs(random_int(PHP_INT_MIN, PHP_INT_MAX)); - $res = $this->externalLine->add($lineNumber, true, sprintf('line-name-%s', $lineNumber)); - $this->assertGreaterThan(0, $res->getExternalLineAddResultItem()->ID); + $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')); } @@ -57,8 +57,8 @@ public function testDeleteExternalLine(): void $this->assertContains($lineNumber, array_column($this->externalLine->get()->getExternalLines(), 'NUMBER')); - $deleteRes = $this->externalLine->delete($lineNumber); - $this->assertEquals([], $deleteRes->getCoreResponse()->getResponseData()->getResult()); + $emptyResult = $this->externalLine->delete($lineNumber); + $this->assertEquals([], $emptyResult->getCoreResponse()->getResponseData()->getResult()); $this->assertNotContains($lineNumber, array_column($this->externalLine->get()->getExternalLines(), 'NUMBER')); } diff --git a/tests/Integration/Services/Telephony/Voximplant/Line/Service/LineTest.php b/tests/Integration/Services/Telephony/Voximplant/Line/Service/LineTest.php index cb37da80..0fec82a9 100644 --- a/tests/Integration/Services/Telephony/Voximplant/Line/Service/LineTest.php +++ b/tests/Integration/Services/Telephony/Voximplant/Line/Service/LineTest.php @@ -36,7 +36,7 @@ public function testOutgoingSipSet(): void $login = Uuid::v4()->toRfc4122(); $password = Uuid::v4()->toRfc4122(); - $addedLine = $this->sip->add( + $sipLineAddedResult = $this->sip->add( PbxType::cloud, $sipTitle, $serverUrl, @@ -44,8 +44,8 @@ public function testOutgoingSipSet(): void $password ); - $this->assertTrue($this->line->outgoingSipSet($addedLine->getLine()->ID)->isSuccess()); - $this->sip->delete($addedLine->getLine()->ID); + $this->assertTrue($this->line->outgoingSipSet($sipLineAddedResult->getLine()->ID)->isSuccess()); + $this->sip->delete($sipLineAddedResult->getLine()->ID); } #[Test] diff --git a/tests/Integration/Services/Telephony/Voximplant/Sip/SipTest.php b/tests/Integration/Services/Telephony/Voximplant/Sip/SipTest.php index da0c3bb4..2d55c0e1 100644 --- a/tests/Integration/Services/Telephony/Voximplant/Sip/SipTest.php +++ b/tests/Integration/Services/Telephony/Voximplant/Sip/SipTest.php @@ -40,7 +40,7 @@ public function testGet(): void $login = Uuid::v4()->toRfc4122(); $password = Uuid::v4()->toRfc4122(); - $addedLine = $this->sip->add( + $sipLineAddedResult = $this->sip->add( PbxType::cloud, $sipTitle, $serverUrl, @@ -48,7 +48,7 @@ public function testGet(): void $password ); $this->assertGreaterThanOrEqual(1, count($this->sip->get()->getLines())); - $this->assertTrue($this->sip->delete($addedLine->getLine()->CONFIG_ID)->isSuccess()); + $this->assertTrue($this->sip->delete($sipLineAddedResult->getLine()->CONFIG_ID)->isSuccess()); } #[Test] @@ -60,18 +60,18 @@ public function testDelete(): void $login = Uuid::v4()->toRfc4122(); $password = Uuid::v4()->toRfc4122(); - $addedLine = $this->sip->add( + $sipLineAddedResult = $this->sip->add( PbxType::cloud, $sipTitle, $serverUrl, $login, $password ); - $this->assertTrue(in_array($addedLine->getLine()->CONFIG_ID, array_column($this->sip->get()->getLines(), 'CONFIG_ID'))); + $this->assertTrue(in_array($sipLineAddedResult->getLine()->CONFIG_ID, array_column($this->sip->get()->getLines(), 'CONFIG_ID'))); - $this->assertTrue($this->sip->delete($addedLine->getLine()->CONFIG_ID)->isSuccess()); + $this->assertTrue($this->sip->delete($sipLineAddedResult->getLine()->CONFIG_ID)->isSuccess()); - $this->assertFalse(in_array($addedLine->getLine()->CONFIG_ID, array_column($this->sip->get()->getLines(), 'CONFIG_ID'))); + $this->assertFalse(in_array($sipLineAddedResult->getLine()->CONFIG_ID, array_column($this->sip->get()->getLines(), 'CONFIG_ID'))); } /** @@ -87,19 +87,19 @@ public function testAdd(): void $login = Uuid::v4()->toRfc4122(); $password = Uuid::v4()->toRfc4122(); - $addedLine = $this->sip->add( + $sipLineAddedResult = $this->sip->add( PbxType::cloud, $sipTitle, $serverUrl, $login, $password ); - $this->assertEquals($sipTitle, $addedLine->getLine()->TITLE); - $this->assertEquals($serverUrl, $addedLine->getLine()->SERVER); - $this->assertEquals($login, $addedLine->getLine()->LOGIN); - $this->assertEquals($password, $addedLine->getLine()->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($addedLine->getLine()->CONFIG_ID)->isSuccess(); + $this->sip->delete($sipLineAddedResult->getLine()->CONFIG_ID)->isSuccess(); } #[Test] @@ -111,7 +111,7 @@ public function testUpdate(): void $login = Uuid::v4()->toRfc4122(); $password = Uuid::v4()->toRfc4122(); - $addedLine = $this->sip->add( + $sipLineAddedResult = $this->sip->add( PbxType::cloud, $sipTitle, $serverUrl, @@ -121,13 +121,13 @@ public function testUpdate(): void $newTitle = 'test sip updated title - ' . Uuid::v4()->toRfc4122(); $this->assertTrue($this->sip->update( - $addedLine->getLine()->CONFIG_ID, - $addedLine->getLine()->TYPE, + $sipLineAddedResult->getLine()->CONFIG_ID, + $sipLineAddedResult->getLine()->TYPE, $newTitle )->isSuccess()); - $this->sip->delete($addedLine->getLine()->CONFIG_ID)->isSuccess(); + $this->sip->delete($sipLineAddedResult->getLine()->CONFIG_ID)->isSuccess(); } #[Test] @@ -139,7 +139,7 @@ public function testStatus(): void $login = Uuid::v4()->toRfc4122(); $password = Uuid::v4()->toRfc4122(); - $addedLine = $this->sip->add( + $sipLineAddedResult = $this->sip->add( PbxType::cloud, $sipTitle, $serverUrl, @@ -147,10 +147,10 @@ public function testStatus(): void $password ); - $sipLineStatus = $this->sip->status($addedLine->getLine()->REG_ID)->getStatus(); - $this->assertEquals($addedLine->getLine()->REG_ID, $sipLineStatus->REG_ID); + $sipLineStatusItemResult = $this->sip->status($sipLineAddedResult->getLine()->REG_ID)->getStatus(); + $this->assertEquals($sipLineAddedResult->getLine()->REG_ID, $sipLineStatusItemResult->REG_ID); - $this->sip->delete($addedLine->getLine()->CONFIG_ID); + $this->sip->delete($sipLineAddedResult->getLine()->CONFIG_ID); } /** From 5707f4ce62c119f0a1bd414e73ed22561482c630 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 22 Jul 2024 01:54:56 +0600 Subject: [PATCH 105/138] Add PHPStan ignore line to test A line to ignore PHPStan analysis was added to the `findByExternalId('')` method call in the `ContactPersonRepositoryInterfaceTest.php` test. This annotative change helps to suppress the PHPStan error that's triggered by this particular line of testing code. Signed-off-by: mesilov --- .../Repository/ContactPersonRepositoryInterfaceTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Unit/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php b/tests/Unit/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php index dfb1d82c..9dc73efb 100644 --- a/tests/Unit/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php +++ b/tests/Unit/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php @@ -442,6 +442,7 @@ final public function testFindByExternalIdWithEmptyId( $contactPersonRepository->save($contactPerson); $this->expectException(InvalidArgumentException::class); + /** @phpstan-ignore-next-line */ $contactPersonRepository->findByExternalId(''); } From 94cb6d54ecd20b858afbe9ef6ee9e7f793a7a044 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 22 Jul 2024 02:26:39 +0600 Subject: [PATCH 106/138] Update PHPUnit fail settings The settings for failOnRisky and failOnWarning within PHPUnit configurations have been updated from true to false. This change allows tests to continue running even if there are risks or warnings, giving the opportunity to see a comprehensive list of all issues rather than stopping at the first one encountered. Signed-off-by: mesilov --- phpunit.xml.dist | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 5b634897..095d8560 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,13 +1,13 @@ - + ./tests/Unit - ./tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php - ./tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterfaceTest.php ./tests/Integration From b94e6775409f939b04a40f0ac45b0b9071908171 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 22 Jul 2024 02:39:37 +0600 Subject: [PATCH 107/138] Refactor test files and update phpunit configuration Test file renaming and reorganizing has been done to streamline namespaces. Additionally, the phpunit configuration has been updated to fail on risky tests. Unused imports have also been removed from various test files, improving code readability. Signed-off-by: mesilov --- phpunit.xml.dist | 2 +- .../Entity/Bitrix24AccountInterfaceTest.php | 4 ++-- .../Bitrix24AccountRepositoryInterfaceTest.php | 3 +-- .../ContactPersons/Entity/ContactPersonInterfaceTest.php | 2 +- .../Repository/ContactPersonRepositoryInterfaceTest.php | 2 +- ...trix24AccountInterfaceReferenceImplementationTest.php | 9 ++++----- ...MemoryBitrix24AccountRepositoryImplementationTest.php | 6 +----- ...ContactPersonInterfaceReferenceImplementationTest.php | 1 + .../InMemoryContactPersonRepositoryImplementation.php | 2 +- ...InMemoryContactPersonRepositoryImplementationTest.php | 2 +- 10 files changed, 14 insertions(+), 19 deletions(-) rename tests/{Unit => }/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php (99%) rename tests/{Unit => }/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterfaceTest.php (99%) rename tests/{Unit => }/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceTest.php (99%) rename tests/{Unit => }/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php (99%) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 095d8560..171b2a98 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,7 +1,7 @@ + bootstrap="tests/bootstrap.php" failOnRisky="true" failOnWarning="true"> diff --git a/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php b/tests/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php similarity index 99% rename from tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php rename to tests/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php index defb1109..21d89660 100644 --- a/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php +++ b/tests/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Tests\Unit\Application\Contracts\Bitrix24Accounts\Entity; +namespace Bitrix24\SDK\Tests\Application\Contracts\Bitrix24Accounts\Entity; use Bitrix24\SDK\Application\ApplicationStatus; use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountInterface; @@ -12,7 +12,6 @@ use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; use Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException; use Bitrix24\SDK\Core\Response\DTO\RenewedAuthToken; -use Bitrix24\SDK\Services\Telephony\Call\Service\Call; use Carbon\CarbonImmutable; use Generator; use PHPUnit\Framework\Attributes\CoversClass; @@ -22,6 +21,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Uid\Uuid; use Throwable; + #[CoversClass(Bitrix24AccountInterface::class)] abstract class Bitrix24AccountInterfaceTest extends TestCase { diff --git a/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterfaceTest.php b/tests/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterfaceTest.php similarity index 99% rename from tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterfaceTest.php rename to tests/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterfaceTest.php index 337724f8..61a93bc3 100644 --- a/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterfaceTest.php +++ b/tests/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterfaceTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Tests\Unit\Application\Contracts\Bitrix24Accounts\Repository; +namespace Bitrix24\SDK\Tests\Application\Contracts\Bitrix24Accounts\Repository; use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountInterface; use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountStatus; @@ -20,7 +20,6 @@ use PHPUnit\Framework\Attributes\TestDox; use PHPUnit\Framework\TestCase; use Symfony\Component\Uid\Uuid; -use Throwable; #[CoversClass(Bitrix24AccountInterface::class)] abstract class Bitrix24AccountRepositoryInterfaceTest extends TestCase diff --git a/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceTest.php b/tests/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceTest.php similarity index 99% rename from tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceTest.php rename to tests/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceTest.php index 46f4f519..866a9067 100644 --- a/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceTest.php +++ b/tests/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Tests\Unit\Application\Contracts\ContactPersons\Entity; +namespace Bitrix24\SDK\Tests\Application\Contracts\ContactPersons\Entity; use Bitrix24\SDK\Application\Contracts\ContactPersons\Entity\ContactPersonInterface; use Bitrix24\SDK\Application\Contracts\ContactPersons\Entity\ContactPersonStatus; diff --git a/tests/Unit/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php b/tests/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php similarity index 99% rename from tests/Unit/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php rename to tests/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php index 9dc73efb..9b67809e 100644 --- a/tests/Unit/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php +++ b/tests/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Tests\Unit\Application\Contracts\ContactPersons\Repository; +namespace Bitrix24\SDK\Tests\Application\Contracts\ContactPersons\Repository; use Bitrix24\SDK\Application\Contracts\ContactPersons\Entity\ContactPersonInterface; use Bitrix24\SDK\Application\Contracts\ContactPersons\Entity\ContactPersonStatus; diff --git a/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceReferenceImplementationTest.php b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceReferenceImplementationTest.php index 7b5f748a..d2135df7 100644 --- a/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceReferenceImplementationTest.php +++ b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceReferenceImplementationTest.php @@ -4,19 +4,18 @@ namespace Bitrix24\SDK\Tests\Unit\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\Tests\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountInterfaceTest; use Carbon\CarbonImmutable; -use Generator; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\TestCase; use Symfony\Component\Uid\Uuid; + #[CoversClass(Bitrix24AccountInterface::class)] -class Bitrix24AccountInterfaceReferenceImplementationTest extends Bitrix24AccountInterfaceTest +class +Bitrix24AccountInterfaceReferenceImplementationTest extends Bitrix24AccountInterfaceTest { protected function createBitrix24AccountImplementation( Uuid $uuid, diff --git a/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementationTest.php b/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementationTest.php index 9e462d2a..771636f5 100644 --- a/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementationTest.php +++ b/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementationTest.php @@ -4,20 +4,16 @@ namespace Bitrix24\SDK\Tests\Unit\Application\Contracts\Bitrix24Accounts\Repository; -use Bitrix24\SDK\Application\ApplicationStatus; 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\Core\Exceptions\InvalidArgumentException; +use Bitrix24\SDK\Tests\Application\Contracts\Bitrix24Accounts\Repository\Bitrix24AccountRepositoryInterfaceTest; use Bitrix24\SDK\Tests\Integration\Fabric; -use Bitrix24\SDK\Tests\Unit\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountInterfaceTest; use Bitrix24\SDK\Tests\Unit\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountReferenceEntityImplementation; use Carbon\CarbonImmutable; -use Generator; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\TestCase; use Symfony\Component\Uid\Uuid; #[CoversClass(Bitrix24AccountRepositoryInterface::class)] diff --git a/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceReferenceImplementationTest.php b/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceReferenceImplementationTest.php index 08602f43..f1abf918 100644 --- a/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceReferenceImplementationTest.php +++ b/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceReferenceImplementationTest.php @@ -6,6 +6,7 @@ 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; diff --git a/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementation.php b/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementation.php index 43a5b79f..90d8dd55 100644 --- a/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementation.php +++ b/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementation.php @@ -9,9 +9,9 @@ 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; -use libphonenumber\PhoneNumber; class InMemoryContactPersonRepositoryImplementation implements ContactPersonRepositoryInterface diff --git a/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementationTest.php b/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementationTest.php index d0e374ce..b69c64a4 100644 --- a/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementationTest.php +++ b/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementationTest.php @@ -11,12 +11,12 @@ 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 Generator; use libphonenumber\PhoneNumber; use PHPUnit\Framework\Attributes\CoversClass; use Symfony\Component\Uid\Uuid; From 00a3f8988c668526e358ffa247e3b429de9ed5a8 Mon Sep 17 00:00:00 2001 From: mesilov Date: Tue, 23 Jul 2024 01:55:05 +0600 Subject: [PATCH 108/138] Add ContactPerson event classes and documentation Created new event classes for the ContactPerson entity in the Application Contracts layer, aimed to deal with various situations such as contact creation, block, unblock, or deletion. Also included is the full documentation file describing ContactPerson's methods, states, repository methods, and events. Signed-off-by: mesilov --- .../ContactPersons/Docs/ContactPersons.md | 96 +++++++++++++++++++ .../Events/ContactPersonBlockedEvent.php | 18 ++++ .../Events/ContactPersonCreatedEvent.php | 18 ++++ .../Events/ContactPersonDeletedEvent.php | 18 ++++ .../Events/ContactPersonEmailChangedEvent.php | 18 ++++ .../ContactPersonEmailVerifiedEvent.php | 18 ++++ .../ContactPersonFullNameChangedEvent.php | 18 ++++ ...ntactPersonLinkedToExternalEntityEvent.php | 18 ++++ .../ContactPersonMobilePhoneChangedEvent.php | 18 ++++ .../ContactPersonMobilePhoneVerifiedEvent.php | 18 ++++ .../Events/ContactPersonUnblockedEvent.php | 18 ++++ 11 files changed, 276 insertions(+) create mode 100644 src/Application/Contracts/ContactPersons/Docs/ContactPersons.md create mode 100644 src/Application/Contracts/ContactPersons/Events/ContactPersonBlockedEvent.php create mode 100644 src/Application/Contracts/ContactPersons/Events/ContactPersonCreatedEvent.php create mode 100644 src/Application/Contracts/ContactPersons/Events/ContactPersonDeletedEvent.php create mode 100644 src/Application/Contracts/ContactPersons/Events/ContactPersonEmailChangedEvent.php create mode 100644 src/Application/Contracts/ContactPersons/Events/ContactPersonEmailVerifiedEvent.php create mode 100644 src/Application/Contracts/ContactPersons/Events/ContactPersonFullNameChangedEvent.php create mode 100644 src/Application/Contracts/ContactPersons/Events/ContactPersonLinkedToExternalEntityEvent.php create mode 100644 src/Application/Contracts/ContactPersons/Events/ContactPersonMobilePhoneChangedEvent.php create mode 100644 src/Application/Contracts/ContactPersons/Events/ContactPersonMobilePhoneVerifiedEvent.php create mode 100644 src/Application/Contracts/ContactPersons/Events/ContactPersonUnblockedEvent.php diff --git a/src/Application/Contracts/ContactPersons/Docs/ContactPersons.md b/src/Application/Contracts/ContactPersons/Docs/ContactPersons.md new file mode 100644 index 00000000..87549ee8 --- /dev/null +++ b/src/Application/Contracts/ContactPersons/Docs/ContactPersons.md @@ -0,0 +1,96 @@ +# 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) | - | +| `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 +- `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/Events/ContactPersonBlockedEvent.php b/src/Application/Contracts/ContactPersons/Events/ContactPersonBlockedEvent.php new file mode 100644 index 00000000..43ca80ef --- /dev/null +++ b/src/Application/Contracts/ContactPersons/Events/ContactPersonBlockedEvent.php @@ -0,0 +1,18 @@ + Date: Wed, 24 Jul 2024 01:47:45 +0600 Subject: [PATCH 109/138] Add application installation interface and Bitrix24 ID to contact person This update adds an application installation interface for setting up interactions between the application and the Bitrix24 API. A Bitrix24 user ID field is also added to the contact person interface. This modification extends the functionality of the contact person, enabling more advanced data tracking. The new ID field maps a Bitrix24 user with a contact person, if there is any association. Signed-off-by: mesilov --- examples/LoggerFactory.php | 22 ++ examples/application/local/.env | 8 + .../application/local/activity-handler.php | 156 +++++++++++ examples/application/local/bp-82.bpt | Bin 0 -> 5819 bytes examples/application/local/index.php | 254 ++++++++++++++++++ examples/application/local/install.php | 14 + examples/application/local/robot-handler.php | 87 ++++++ examples/core/webhook/.env | 5 + examples/core/webhook/composer.json | 21 ++ examples/core/webhook/example.php | 30 +++ examples/services/telephony/.env | 9 + .../services/telephony/events-handler.php | 122 +++++++++ examples/services/telephony/index.php | 63 +++++ examples/services/telephony/install.php | 4 + examples/services/workflows/.env | 5 + examples/services/workflows/task.php | 131 +++++++++ examples/services/workflows/workflow.php | 159 +++++++++++ .../Docs/ApplicationInstallations.md | 15 ++ .../ApplicationInstallationInterface.php | 67 +++++ .../ContactPersons/Docs/ContactPersons.md | 51 ++-- .../Entity/ContactPersonInterface.php | 5 + .../Entity/ContactPersonInterfaceTest.php | 108 ++++++-- .../ContactPersonRepositoryInterfaceTest.php | 51 ++-- ...onInterfaceReferenceImplementationTest.php | 2 + ...actPersonReferenceEntityImplementation.php | 6 + ...tactPersonRepositoryImplementationTest.php | 2 + 26 files changed, 1331 insertions(+), 66 deletions(-) create mode 100644 examples/LoggerFactory.php create mode 100644 examples/application/local/.env create mode 100644 examples/application/local/activity-handler.php create mode 100644 examples/application/local/bp-82.bpt create mode 100644 examples/application/local/index.php create mode 100644 examples/application/local/install.php create mode 100644 examples/application/local/robot-handler.php create mode 100644 examples/core/webhook/.env create mode 100644 examples/core/webhook/composer.json create mode 100644 examples/core/webhook/example.php create mode 100644 examples/services/telephony/.env create mode 100644 examples/services/telephony/events-handler.php create mode 100644 examples/services/telephony/index.php create mode 100644 examples/services/telephony/install.php create mode 100644 examples/services/workflows/.env create mode 100644 examples/services/workflows/task.php create mode 100644 examples/services/workflows/workflow.php create mode 100644 src/Application/Contracts/ApplicationInstallations/Docs/ApplicationInstallations.md create mode 100644 src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterface.php diff --git a/examples/LoggerFactory.php b/examples/LoggerFactory.php new file mode 100644 index 00000000..bb18fcdb --- /dev/null +++ b/examples/LoggerFactory.php @@ -0,0 +1,22 @@ +pushHandler(new StreamHandler($_ENV['LOGS_FILE_NAME'], (int)$_ENV['LOGS_LEVEL'])); + $log->pushProcessor(new MemoryUsageProcessor(true, true)); + $log->pushProcessor(new IntrospectionProcessor((int)$_ENV['LOGS_LEVEL'])); + + return $log; + } +} \ No newline at end of file diff --git a/examples/application/local/.env b/examples/application/local/.env new file mode 100644 index 00000000..ef1ad926 --- /dev/null +++ b/examples/application/local/.env @@ -0,0 +1,8 @@ +# 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= \ No newline at end of file diff --git a/examples/application/local/activity-handler.php b/examples/application/local/activity-handler.php new file mode 100644 index 00000000..fbb6af41 --- /dev/null +++ b/examples/application/local/activity-handler.php @@ -0,0 +1,156 @@ + +
+    Приложение работает, получили токены от Битрикс24:
+    
+
+bootEnv('.env'); + +if ($_SERVER['APP_DEBUG']) { + umask(0000); + + if (class_exists( + Debug::class + )) { + Debug::enable(); + } +} + + +try { + $log = new Logger('bitrix24-php-sdk-cli'); + $log->pushHandler(new StreamHandler($_ENV['LOGS_FILE_NAME'], (int)$_ENV['LOGS_LEVEL'])); + $log->pushProcessor(new MemoryUsageProcessor(true, true)); + + $req = Request::createFromGlobals(); + $log->debug('incoming request', [ + 'payload' => $req->request->all() + ]); + + $workflowReq = IncomingRobotRequest::initFromRequest($req); + + print_r($workflowReq); + + $b24ServiceFactory = new ServiceBuilderFactory(new EventDispatcher(), $log); + $appProfile = ApplicationProfile::initFromArray($_ENV); + + //AccessToken::initFromWorkflowRequest($req), + $b24Service = $b24ServiceFactory->initFromRequest( + $appProfile, + $workflowReq->auth->accessToken, + $workflowReq->auth->domain + ); + + $returnProp = [ + 'result_sum' => 5555 + ]; + + print('PROP' . PHP_EOL); + print_r($workflowReq->properties); + print_r($b24Service->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()); + + $b24Service->getBizProcScope()->activity()->log( + $workflowReq->eventToken, + 'hello from activity handler' + ); + + $res = $b24Service->getBizProcScope()->event()->send( + $workflowReq->eventToken, + $returnProp, + sprintf('debug result %s', print_r($returnProp, true)) + ); + $log->debug('ffffffff', [ + 'res' => $res->isSuccess() + ]); + +} catch (Throwable $exception) { + + $log->error(sprintf('error: %s', $exception->getMessage()), [ + 'trace' => $exception->getTraceAsString() + ]); + + print('ERRRRRRRRRORRRR!!!!'); + print($exception->getMessage() . PHP_EOL); + print_r($exception->getTraceAsString()); + +} + + +// Array +// ( +// [workflow_id] => 664fa13bbbb410.99176768 +// [code] => test_activity +// [document_id] => Array +// ( +// [0] => crm +// [1] => CCrmDocumentContact +// [2] => CONTACT_109286 +// ) +// +// [document_type] => Array +// ( +// [0] => crm +// [1] => CCrmDocumentContact +// [2] => CONTACT +// ) +// +// [event_token] => 664fa13bbbb410.99176768|A40364_79843_85254_57332|MS1ekdI0CvXi8ycL8qNIn96hak8JEndG.54020ce210345fb6eb12a79d75316d9430b42ccd9c1d82ab1a3bf8b064ec50e9 +// [properties] => Array +// ( +// [comment] => дефолтная строка - значение +// [amount] => 333 +// ) +// +// [use_subscription] => Y +// [timeout_duration] => 660 +// [ts] => 1716494651 + +// [auth] => Array +// ( + +// access token +// [access_token] => 4baf4f66006e13540058f18a000000100000009b41bce7ec85f07c3646c07e6d629e7c +// [refresh_token] => 3b2e7766006e13540058f18a000000100000003b31a96730e79dc7561c1d7d0b33933f +// [expires] => 1716498251 + +// endpoints +// [server_endpoint] => https://oauth.bitrix.info/rest/ +// [client_endpoint] => https://bitrix24-php-sdk-playground.bitrix24.ru/rest/ + +// scope +// [scope] => crm,bizproc,appform,baas,placement,user_brief,call,telephony + +// application status +// [status] => L + + +// [application_token] => f9ac5db5ad4adbdee13eb034207d8fbd +// [expires_in] => 3600 +// [domain] => bitrix24-php-sdk-playground.bitrix24.ru +// [member_id] => 010b6886ebc205e43ae65000ee00addb +// [user_id] => 16 +// ) +//) diff --git a/examples/application/local/bp-82.bpt b/examples/application/local/bp-82.bpt new file mode 100644 index 0000000000000000000000000000000000000000..227b054cf989a7531b029c042fe24f5ab2390209 GIT binary patch literal 5819 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 FgH402c^?1( literal 0 HcmV?d00001 diff --git a/examples/application/local/index.php b/examples/application/local/index.php new file mode 100644 index 00000000..6a6e55d3 --- /dev/null +++ b/examples/application/local/index.php @@ -0,0 +1,254 @@ + +
+    Приложение работает, получили токены от Битрикс24:
+    
+
+bootEnv('.env'); + +if ($_SERVER['APP_DEBUG']) { + umask(0000); + + if (class_exists( + Debug::class + )) { + Debug::enable(); + } +} + +$request = Request::createFromGlobals(); + + +$log = new Logger('bitrix24-php-sdk-cli'); +$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); +$b24Service = $b24ServiceFactory->initFromRequest($appProfile, AuthToken::initFromPlacementRequest($request), $_REQUEST['DOMAIN']); + + +var_dump('Hello world'); + +var_dump(Bitrix24\SDK\Core\Credentials\Credentials::createFromPlacementRequest( + new \Bitrix24\SDK\Application\Requests\Placement\PlacementRequest($request), + $appProfile +)->getAuthToken()); +// +//$b64 = new \Symfony\Component\Mime\Encoder\Base64Encoder(); +//$str = $b64->encodeString(file_get_contents('bp-82.bpt')); + + +// run workflow +//var_dump($b24Service->getBizProcScope()->template()->delete(82)); + +//$templateId = $b24Service->getBizProcScope()->template()->add( +// WorkflowDocumentType::buildForContact(), +// 'Test template', +// 'Test template description', +// WorkflowAutoExecutionType::withoutAutoExecution, +// 'bp-82.bpt' +//)->getId(); +// +//$updateResult = $b24Service->getBizProcScope()->template()->update( +// $templateId, +// null, +// 'updated name', +// null, +// null, +// 'bp-82.bpt' +//)->isSuccess(); +// +//var_dump($updateResult); + + +// +// +//foreach ($b24Service->getBizProcScope()->activity()->list()->getActivities() as $activityCode) { +// var_dump($activityCode); +// var_dump($b24Service->getBizProcScope()->activity()->delete($activityCode)->isSuccess()); +//} +//$activityCode = 'test_activity'; +//$handlerUrl = 'https://' . $_SERVER['HTTP_HOST'] . '/activity-handler.php'; +//$b24AdminUserId = $b24Service->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()->ID; +//$activityName = [ +// 'ru' => 'Название активити', +// 'en' => 'activity name' +//]; +//$activityDescription = [ +// 'ru' => 'Описание активити', +// 'en' => 'Activity description' +//]; +//$activityProperties = [ +// 'comment' => [ +// 'Name' => [ +// 'ru' => 'строка desc', +// 'en' => 'string desc' +// ], +// 'Description' => [ +// 'ru' => 'строка desc', +// 'en' => 'string desc' +// ], +// 'Type' => WorkflowPropertyType::string->name, +// 'Options' => null, +// 'Required' => 'N', +// 'Multiple' => 'N', +// 'Default' => 'дефолтная строка - значение' +// +// ], +// 'amount' => [ +// 'Name' => [ +// 'ru' => 'int значение', +// 'en' => 'int value' +// ], +// 'Description' => [ +// 'ru' => 'int значение пример', +// 'en' => 'int value example' +// ], +// 'Type' => WorkflowPropertyType::int->name, +// 'Options' => null, +// 'Required' => 'N', +// 'Multiple' => 'N', +// 'Default' => 333 +// ] +//]; +// +//$activityReturnProperties = [ +// 'result_sum' => [ +// 'Name' => [ +// 'ru' => 'int значение', +// 'en' => 'int value' +// ], +// 'Description' => [ +// 'ru' => 'int', +// 'en' => 'int' +// ], +// 'Type' => WorkflowPropertyType::int->name, +// 'Options' => null, +// 'Required' => 'N', +// 'Multiple' => 'N', +// 'Default' => 444 +// ] +//]; +// +// +//$addActivityResult = $b24Service->getBizProcScope()->activity()->add( +// $activityCode, +// $handlerUrl, +// $b24AdminUserId, +// $activityName, +// $activityDescription, +// true, +// $activityProperties, +// false, +// $activityReturnProperties, +// WorkflowDocumentType::buildForLead(), +// [] +//); +// +//var_dump($addActivityResult->getCoreResponse()->getResponseData()->getResult()); +// +// +// +//print('delete robots...' . PHP_EOL); +//foreach ($b24Service->getBizProcScope()->robot()->list()->getRobots() as $robotCode) { +// print_r($b24Service->getBizProcScope()->robot()->delete($robotCode)->isSuccess()); +//} +// +// +//$robotProperties = [ +// 'comment' => [ +// 'Name' => [ +// 'ru' => 'строка desc', +// 'en' => 'string desc' +// ], +// 'Description' => [ +// 'ru' => 'строка desc', +// 'en' => 'string desc' +// ], +// 'Type' => WorkflowPropertyType::string->name, +// 'Options' => null, +// 'Required' => 'N', +// 'Multiple' => 'N', +// 'Default' => 'дефолтная строка - значение' +// +// ], +// 'amount' => [ +// 'Name' => [ +// 'ru' => 'int значение', +// 'en' => 'int value' +// ], +// 'Description' => [ +// 'ru' => 'int значение пример', +// 'en' => 'int value example' +// ], +// 'Type' => WorkflowPropertyType::int->name, +// 'Options' => null, +// 'Required' => 'N', +// 'Multiple' => 'N', +// 'Default' => 333 +// ] +//]; +// +//$robotReturnProperties = [ +// 'result_sum' => [ +// 'Name' => [ +// 'ru' => 'int значение', +// 'en' => 'int value' +// ], +// 'Description' => [ +// 'ru' => 'int', +// 'en' => 'int' +// ], +// 'Type' => WorkflowPropertyType::int->name, +// 'Options' => null, +// 'Required' => 'N', +// 'Multiple' => 'N', +// 'Default' => 'дефолтная строка - значение' +// ] +//]; +// +//$handlerUrl = 'https://' . $_SERVER['HTTP_HOST'] . '/robot-handler.php'; +//var_dump($handlerUrl); +//print('install robots...' . PHP_EOL); +//$addResult = $b24Service->getBizProcScope()->robot()->add('test_r_1', $handlerUrl, +// 1, +// [ +// 'ru' => 'РОБОТ 1', +// 'en' => 'robot 1', +// ], +// true, +// $robotProperties, +// false, +// $robotReturnProperties +//); +// +//var_dump($addResult->isSuccess()); +//// +//var_dump($b24Service->getBizProcScope()->robot()->list()->getRobots()); +//// +// diff --git a/examples/application/local/install.php b/examples/application/local/install.php new file mode 100644 index 00000000..31cd5b2a --- /dev/null +++ b/examples/application/local/install.php @@ -0,0 +1,14 @@ + +
+    Установка приложения, получили токены от Битрикс24:
+    
+
+ + \ No newline at end of file diff --git a/examples/application/local/robot-handler.php b/examples/application/local/robot-handler.php new file mode 100644 index 00000000..ab923878 --- /dev/null +++ b/examples/application/local/robot-handler.php @@ -0,0 +1,87 @@ + +
+    Приложение работает, получили токены от Битрикс24:
+    
+
+bootEnv('.env'); + +if ($_SERVER['APP_DEBUG']) { + umask(0000); + + if (class_exists( + Debug::class + )) { + Debug::enable(); + } +} + + +try { + $log = new Logger('bitrix24-php-sdk-cli'); + $log->pushHandler(new StreamHandler($_ENV['LOGS_FILE_NAME'], (int)$_ENV['LOGS_LEVEL'])); + $log->pushProcessor(new MemoryUsageProcessor(true, true)); + + $req = Request::createFromGlobals(); + $log->debug('incoming request', [ + 'payload' => $req->request->all() + ]); + + $b24ServiceFactory = new ServiceBuilderFactory(new EventDispatcher(), $log); + $appProfile = ApplicationProfile::initFromArray($_ENV); + + + $rr = IncomingRobotRequest::initFromRequest($req); + + $b24Service = $b24ServiceFactory->initFromRequest( + $appProfile, + $rr->auth->accessToken, + $rr->auth->domain + ); + + $returnProp = [ + 'result_sum' => 5555 + ]; + + $res = $b24Service->getBizProcScope()->event()->send( + $rr->eventToken, + $returnProp, + sprintf('debug result %s', print_r($returnProp, true)) + ); + $log->debug('ffffffff', [ + 'res' => $res->isSuccess() + ]); + +} catch (Throwable $exception) { + + $log->error(sprintf('error: %s', $exception->getMessage()), [ + 'trace' => $exception->getTraceAsString() + ]); + + +} + + diff --git a/examples/core/webhook/.env b/examples/core/webhook/.env new file mode 100644 index 00000000..1355fb8e --- /dev/null +++ b/examples/core/webhook/.env @@ -0,0 +1,5 @@ +# bitrix24 webhook url +BITRIX24_WEBHOOK_URL= +# monolog +LOG_LEVEL=100 +LOG_FILE_NAME=bitrix24-php-sdk.log diff --git a/examples/core/webhook/composer.json b/examples/core/webhook/composer.json new file mode 100644 index 00000000..11c0dc0c --- /dev/null +++ b/examples/core/webhook/composer.json @@ -0,0 +1,21 @@ +{ + "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-371-publish-b24-php-sdk-beta-2", + "monolog/monolog": "3.5.*", + "symfony/dotenv": "7.0.*", + + }, + "require-dev": { + "roave/security-advisories": "dev-latest" + } +} \ No newline at end of file diff --git a/examples/core/webhook/example.php b/examples/core/webhook/example.php new file mode 100644 index 00000000..03e40fd2 --- /dev/null +++ b/examples/core/webhook/example.php @@ -0,0 +1,30 @@ +loadEnv('.env'); +$webhookUrl = $_ENV['BITRIX24_WEBHOOK_URL']; + +// configure logger for debug queries +$log = new Logger('bitrix24-php-sdk'); +$log->pushHandler(new StreamHandler($_ENV['LOG_FILE_NAME'], (int)$_ENV['LOG_LEVEL'])); +$log->pushProcessor(new MemoryUsageProcessor(true, true)); +$log->pushProcessor(new IntrospectionProcessor()); + +// create factory for build service from multiple sources: webhook, request, bitrix24 account with oauth2.0 tokens +$b24ServiceFactory = new ServiceBuilderFactory(new EventDispatcher(), $log); +// init bitrix24-php-sdk service with webhook credentials +$b24Service = $b24ServiceFactory->initFromWebhook($webhookUrl); + +$deal = $b24Service->getCRMScope()->deal()->get(1)->deal(); +var_dump($deal->TITLE); \ No newline at end of file diff --git a/examples/services/telephony/.env b/examples/services/telephony/.env new file mode 100644 index 00000000..a15fc445 --- /dev/null +++ b/examples/services/telephony/.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/examples/services/telephony/events-handler.php b/examples/services/telephony/events-handler.php new file mode 100644 index 00000000..cfd23535 --- /dev/null +++ b/examples/services/telephony/events-handler.php @@ -0,0 +1,122 @@ +bootEnv('.env'); + +if ($_SERVER['APP_DEBUG']) { + umask(0000); + + if (class_exists( + Debug::class + )) { + Debug::enable(); + } +} + +try { + + $log = LoggerFactory::get(); + + $request = Request::createFromGlobals(); + $log->debug('incoming request', [ + 'payload' => $request->request->all() + ]); + + // create telephony event + $event = (new TelephonyEventsFabric())->create($request); + if ($event === null) { + throw new \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException('unknown event code'); + } + $log->debug('received event', [ + 'code' => $event->getEventCode(), + 'payload' => $event->getEventPayload(), + ]); + + // init service builder with auth token from event + $serviceBuilder = (new ServiceBuilderFactory(new EventDispatcher(), $log))->initFromRequest( + ApplicationProfile::initFromArray($_ENV), + AuthToken::initFromEventRequest($request), + $event->getAuth()->client_endpoint + ); + + $curUser = $serviceBuilder->getMainScope()->main()->getCurrentUserProfile()->getUserProfile(); + $log->debug('current user profile', [ + 'id' => $curUser->ID + ]); + $currentB24UserId = $serviceBuilder->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()->ID; + $innerPhoneNumber = '123'; + // set inner phone number for user + $serviceBuilder->getUserScope()->user()->update( + $currentB24UserId, + [ + 'UF_PHONE_INNER' => $innerPhoneNumber + ] + ); + + if ($event instanceof Bitrix24\SDK\Services\Telephony\Events\OnExternalCallBackStart\OnExternalCallBackStart) { + // start call + $phoneNumber = '7978' . random_int(1000000, 9999999); + $b24CallId = $serviceBuilder->getTelephonyScope()->externalCall()->register( + $innerPhoneNumber, + $currentB24UserId, + $phoneNumber, + CarbonImmutable::now(), + CallType::outbound, + true, + true, + '3333', + null, + CrmEntityType::contact + )->getExternalCallRegistered()->CALL_ID; + + //emulate work with external pbx and make real call + sleep(3); + + // finish call + $money = new Money(10000, new Currency('USD')); + $duration = 100; + $finishResult = $serviceBuilder->getTelephonyScope()->externalCall()->finishForUserId( + $b24CallId, + $currentB24UserId, + $duration, + $money, + TelephonyCallStatusCode::successful, + true + ); + } + if ($event instanceof Bitrix24\SDK\Services\Telephony\Events\OnVoximplantCallEnd\OnVoximplantCallEnd) { + $log->debug('OnVoximplantCallEnd event payload', [ + 'paylload' => $event->getEventPayload() + ]); + } +} catch (Throwable $exception) { + + $log->error(sprintf('error: %s', $exception->getMessage()), [ + 'trace' => $exception->getTraceAsString() + ]); + + +} + + diff --git a/examples/services/telephony/index.php b/examples/services/telephony/index.php new file mode 100644 index 00000000..e26e5007 --- /dev/null +++ b/examples/services/telephony/index.php @@ -0,0 +1,63 @@ + +
+bootEnv('.env'); + +if ($_SERVER['APP_DEBUG']) { + umask(0000); + if (class_exists( + Debug::class + )) { + Debug::enable(); + } +} + +$request = Request::createFromGlobals(); + +$log = LoggerFactory::get(); + +$b24ServiceFactory = new ServiceBuilderFactory(new EventDispatcher(), $log); +$appProfile = ApplicationProfile::initFromArray($_ENV); +$accessToken = AuthToken::initFromPlacementRequest($request); +$b24Service = $b24ServiceFactory->initFromRequest($appProfile, $accessToken, $_REQUEST['DOMAIN']); + + +// subscribe to all events +$handlerUrl = 'https://' . $request->getHost() . '/events-handler.php'; +$b24UserId = $b24Service->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()->ID; +$eventHandlers = [ + new EventHandlerMetadata(OnExternalCallBackStart::CODE, $handlerUrl, $b24UserId), + new EventHandlerMetadata(OnExternalCallStart::CODE, $handlerUrl, $b24UserId), + new EventHandlerMetadata(OnVoximplantCallInit::CODE, $handlerUrl, $b24UserId), + new EventHandlerMetadata(OnVoximplantCallEnd::CODE, $handlerUrl, $b24UserId), + new EventHandlerMetadata(OnVoximplantCallStart::CODE, $handlerUrl, $b24UserId) +]; + + +$b24Service->getMainScope()->eventManager()->bindEventHandlers($eventHandlers); diff --git a/examples/services/telephony/install.php b/examples/services/telephony/install.php new file mode 100644 index 00000000..eae01705 --- /dev/null +++ b/examples/services/telephony/install.php @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/examples/services/workflows/.env b/examples/services/workflows/.env new file mode 100644 index 00000000..24a48adf --- /dev/null +++ b/examples/services/workflows/.env @@ -0,0 +1,5 @@ +# bitrix24 webhook url +BITRIX24_WEBHOOK= +# monolog +LOGS_LEVEL=100 +LOGS_FILE_NAME=bitrix24-php-sdk.log \ No newline at end of file diff --git a/examples/services/workflows/task.php b/examples/services/workflows/task.php new file mode 100644 index 00000000..7f476f6d --- /dev/null +++ b/examples/services/workflows/task.php @@ -0,0 +1,131 @@ +#!/usr/bin/env php +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('.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_NAME'], (int)$_ENV['LOGS_LEVEL'])); +$log->pushProcessor(new MemoryUsageProcessor(true, true)); + +$webhookUrl = $_ENV['BITRIX24_WEBHOOK']; +$b24ServiceFactory = new ServiceBuilderFactory(new EventDispatcher(), $log); +// init bitrix24-php-sdk service with webhook credentials +$b24Service = $b24ServiceFactory->initFromWebhook($webhookUrl); + +#[AsCommand( + name: 'bitrix24-php-sdk:examples:workflows:task', + hidden: false +)] +class task extends Command +{ + private LoggerInterface $log; + private ServiceBuilder $serviceBuilder; + + public function __construct(ServiceBuilder $serviceBuilder, 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->log = $logger; + $this->serviceBuilder = $serviceBuilder; + parent::__construct(); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $output->writeln([ + 'Work with workflow task example', + ]); + + + var_dump($this->serviceBuilder->getBizProcScope()->task()->list( + [], + [], + [ + 'ID', + 'WORKFLOW_ID', + 'DOCUMENT_NAME', + 'DESCRIPTION', + 'NAME', + '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' + ])->getTasks()); + + $this->serviceBuilder->getBizProcScope()->task()->complete( + 2, + \Bitrix24\SDK\Services\Workflows\Common\WorkflowTaskCompleteStatusType::approved, + 'oook' + ); + + + return 0; + } +} + +$application = new Application(); +$application->add(new task($b24Service, $log)); +$application->run($input); diff --git a/examples/services/workflows/workflow.php b/examples/services/workflows/workflow.php new file mode 100644 index 00000000..776c1eaf --- /dev/null +++ b/examples/services/workflows/workflow.php @@ -0,0 +1,159 @@ +#!/usr/bin/env php +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('.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_NAME'], (int)$_ENV['LOGS_LEVEL'])); +$log->pushProcessor(new MemoryUsageProcessor(true, true)); + +$webhookUrl = $_ENV['BITRIX24_WEBHOOK']; +$b24ServiceFactory = new ServiceBuilderFactory(new EventDispatcher(), $log); +// init bitrix24-php-sdk service with webhook credentials +$b24Service = $b24ServiceFactory->initFromWebhook($webhookUrl); + +#[AsCommand( + name: 'bitrix24-php-sdk:examples:workflows:workflow', + hidden: false +)] +class workflow extends Command +{ + private LoggerInterface $log; + private ServiceBuilder $serviceBuilder; + + public function __construct(ServiceBuilder $serviceBuilder, 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->log = $logger; + $this->serviceBuilder = $serviceBuilder; + parent::__construct(); + } + + protected function configure(): void + { + $this + ->setDescription('Example of work with workflows') + ->setHelp('Run workflow for contact') + ->addOption( + 'workflow-template-id', + null, + InputOption::VALUE_REQUIRED, + 'workflow template id', + ) + ->addOption( + 'contact-id', + null, + InputOption::VALUE_REQUIRED, + 'Bitrix24 contact id', + ); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $workflowTemplateId = $input->getOption('workflow-template-id'); + $contactId = $input->getOption('contact-id'); + if ($workflowTemplateId === null) { + throw new InvalidArgumentException('Missing workflow template id, you must set workflow-template-id'); + } + if ($contactId === null) { + throw new InvalidArgumentException('Missing contact id, you must set contact-id'); + } + $output->writeln([ + 'Work with workflow example', + '', + sprintf('workflow template id: %s', $workflowTemplateId), + sprintf('contact id: %s', $contactId), + '', + 'run workflow for contact...' + ]); + + // run workflow + $workflowInstanceId = $this->serviceBuilder->getBizProcScope()->workflow()->start( + DocumentType::crmContact, + $workflowTemplateId, + $contactId, + )->getRunningWorkflowInstanceId(); + $output->writeln(sprintf('running workflow instance id: %s', $workflowInstanceId)); + + // get running workflow instance list + $workflowInstances = $this->serviceBuilder->getBizProcScope()->workflow()->instances( + [], + [], + [ + 'ENTITY' => DocumentType::crmContact->value + ] + )->getInstances(); + var_dump($workflowInstances); + + + // try to terminate workflow + $terminationResult = $this->serviceBuilder->getBizProcScope()->workflow()->terminate( + $workflowInstanceId, + 'terminated!' + ); + + var_dump($terminationResult->isSuccess()); + + + return 0; + } +} + +$application = new Application(); +$application->add(new workflow($b24Service, $log)); +$application->run($input); diff --git a/src/Application/Contracts/ApplicationInstallations/Docs/ApplicationInstallations.md b/src/Application/Contracts/ApplicationInstallations/Docs/ApplicationInstallations.md new file mode 100644 index 00000000..2efc0228 --- /dev/null +++ b/src/Application/Contracts/ApplicationInstallations/Docs/ApplicationInstallations.md @@ -0,0 +1,15 @@ + +Install Start +- add ?contact person +- add b24 Account +- add / find b24 partner +- add new installation in mode new + +Install Finish +- b24 account mark as active +- installation mark as active + +Uninstall +- ?delete contact person +- delete b24 account +- mark installation as deleted \ 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..9599a314 --- /dev/null +++ b/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterface.php @@ -0,0 +1,67 @@ +createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $this->assertEquals($uuid, $contactPerson->getId()); } @@ -85,12 +87,13 @@ final public function testGetStatus( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $this->assertEquals($contactPersonStatus, $contactPerson->getStatus()); } @@ -111,12 +114,13 @@ final public function testMarkAsActive( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $contactPerson->markAsBlocked('block contact person'); $this->assertEquals(ContactPersonStatus::blocked, $contactPerson->getStatus()); $message = 'unblock contact person'; @@ -142,12 +146,13 @@ final public function testMarkAsBlocked( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $message = 'block contact person'; $contactPerson->markAsBlocked($message); $this->assertEquals(ContactPersonStatus::blocked, $contactPerson->getStatus()); @@ -171,12 +176,13 @@ final public function testMarkAsDeleted( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $message = 'soft delete contact person'; $contactPerson->markAsDeleted($message); $this->assertEquals(ContactPersonStatus::deleted, $contactPerson->getStatus()); @@ -200,12 +206,13 @@ final public function testMarkAsDeletedBlockedAccount( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $message = 'block contact person'; $contactPerson->markAsBlocked($message); $this->assertEquals(ContactPersonStatus::blocked, $contactPerson->getStatus()); @@ -233,12 +240,13 @@ final public function testMarkAsDeletedDeletedAccount( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $message = 'soft delete contact person'; $contactPerson->markAsDeleted($message); $this->expectException(InvalidArgumentException::class); @@ -262,12 +270,13 @@ final public function testGetFullName( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $this->assertEquals(new FullName($name, $surname, $patronymic), $contactPerson->getFullName()); } @@ -288,12 +297,13 @@ final public function testChangeFullName( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $newFullName = DemoDataGenerator::getFullName(); $contactPerson->changeFullName($newFullName); $this->assertEquals($newFullName, $contactPerson->getFullName()); @@ -316,12 +326,13 @@ final public function testGetUpdatedAt( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $contactPerson->markAsBlocked('test block'); $this->assertEquals($createdAt, $contactPerson->getCreatedAt()); $this->assertNotEquals($updatedAt, $contactPerson->getUpdatedAt()); @@ -344,12 +355,13 @@ final public function testCreatedAt( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $this->assertEquals($createdAt, $contactPerson->getCreatedAt()); } @@ -370,12 +382,13 @@ final public function testGetEmail( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $this->assertEquals($email, $contactPerson->getEmail()); } @@ -396,12 +409,13 @@ final public function testChangeEmail( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $newEmail = DemoDataGenerator::getEmail(); $contactPerson->changeEmail($newEmail); @@ -440,12 +454,13 @@ final public function testMarkEmailAsVerified( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $newEmail = DemoDataGenerator::getEmail(); // email not verified @@ -473,12 +488,13 @@ final public function testGetMobilePhone( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $this->assertEquals($phoneNumber, $contactPerson->getMobilePhone()); } @@ -499,12 +515,13 @@ final public function testChangeMobilePhone( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $phone = DemoDataGenerator::getMobilePhone(); $contactPerson->changeMobilePhone($phone); @@ -536,12 +553,13 @@ final public function testGetMobilePhoneVerifiedAt( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $this->assertEquals($phoneNumber, $contactPerson->getMobilePhone()); $phone = DemoDataGenerator::getMobilePhone(); @@ -566,12 +584,13 @@ final public function testMarkMobilePhoneAsVerified( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $this->assertEquals($phoneNumber, $contactPerson->getMobilePhone()); $phone = DemoDataGenerator::getMobilePhone(); @@ -598,12 +617,13 @@ final public function testGetComment( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $comment = 'block reason'; $contactPerson->markAsBlocked($comment); $this->assertEquals($comment, $contactPerson->getComment()); @@ -626,12 +646,13 @@ final public function testSetExternalId( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $uuidV7 = Uuid::v7(); $contactPerson->setExternalId($uuidV7->toRfc4122()); @@ -655,21 +676,54 @@ final public function testGetExternalId( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?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, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $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, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $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, + ?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, $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, $userAgent, $userAgentReferer, $userAgentIp); + $this->assertEquals($bitrix24UserId, $contactPerson->getBitrix24UserId()); + } + #[Test] #[DataProvider('contactPersonDataProvider')] #[TestDox('test getUserAgent method')] @@ -687,12 +741,13 @@ final public function testGetUserAgent( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $this->assertEquals($userAgent, $contactPerson->getUserAgent()); } @@ -713,12 +768,13 @@ final public function testGetUserAgentReferer( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $this->assertEquals($userAgentReferer, $contactPerson->getUserAgentReferer()); } @@ -739,12 +795,13 @@ final public function testGetUserAgentIp( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp ): void { - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $this->assertEquals($userAgentIp, $contactPerson->getUserAgentIp()); } @@ -766,6 +823,7 @@ public static function contactPersonDataProvider(): Generator DemoDataGenerator::getMobilePhone(), CarbonImmutable::now(), null, + null, DemoDataGenerator::getUserAgent(), 'https://bitrix24.com/apps/store?utm_source=bx24', DemoDataGenerator::getUserAgentIp() diff --git a/tests/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php b/tests/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php index 9b67809e..2cff13a6 100644 --- a/tests/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php +++ b/tests/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php @@ -38,6 +38,7 @@ abstract protected function createContactPersonImplementation( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp @@ -65,13 +66,14 @@ final public function testSave( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?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, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $contactPersonRepository->save($contactPerson); $acc = $contactPersonRepository->getById($contactPerson->getId()); @@ -99,13 +101,14 @@ final public function testDelete( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?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, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $contactPersonRepository->save($contactPerson); $contactPerson = $contactPersonRepository->getById($contactPerson->getId()); @@ -137,13 +140,14 @@ final public function testDeleteWithUnsavedElement( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?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, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $this->expectException(ContactPersonNotFoundException::class); $contactPersonRepository->delete($contactPerson->getId()); @@ -169,13 +173,14 @@ final public function testGetById( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?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, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $contactPersonRepository->save($contactPerson); $acc = $contactPersonRepository->getById($contactPerson->getId()); @@ -199,6 +204,7 @@ final public function testGetByIdWithNonExist( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp @@ -227,13 +233,14 @@ final public function testFindByEmailWithHappyPath( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?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, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $contactPersonRepository->save($contactPerson); $contactPersons = $contactPersonRepository->findByEmail($email); @@ -257,13 +264,14 @@ final public function testFindByEmailWithNonExistsEmail( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?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, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $contactPersonRepository->save($contactPerson); $contactPersons = $contactPersonRepository->findByEmail('this.email.doesnt.exists@b24.com'); @@ -287,13 +295,14 @@ final public function testFindByEmailWithDifferentStatuses( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?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, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $contactPersonRepository->save($contactPerson); $contactPersons = $contactPersonRepository->findByEmail($email, $contactPersonStatus); @@ -308,8 +317,8 @@ 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, $userAgent, $userAgentReferer, $userAgentIp] = $item; - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + [$uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp] = $item; + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $contactPersonRepository->save($contactPerson); if (!$expectedContactPerson instanceof ContactPersonInterface) { $expectedContactPerson = $contactPerson; @@ -330,8 +339,8 @@ 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, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp] = $item; - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + [$uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp] = $item; + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $contactPersonRepository->save($contactPerson); if (!$expectedContactPerson instanceof ContactPersonInterface) { $expectedContactPerson = $contactPerson; @@ -364,13 +373,14 @@ final public function testFindByExternalId( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?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, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $externalId = Uuid::v7(); $contactPerson->setExternalId($externalId->toRfc4122()); @@ -400,13 +410,14 @@ final public function testFindByExternalIdWithNonExistsId( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?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, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $contactPersonRepository->save($contactPerson); $this->assertEquals([], $contactPersonRepository->findByExternalId(Uuid::v7()->toRfc4122())); @@ -432,13 +443,14 @@ final public function testFindByExternalIdWithEmptyId( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?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, $userAgent, $userAgentReferer, $userAgentIp); + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $contactPersonRepository->save($contactPerson); $this->expectException(InvalidArgumentException::class); @@ -455,8 +467,8 @@ final public function testFindByExternalIdWithMultipleInstalls(array $items): vo $expectedContactPersons = []; $expectedExternalId = null; foreach ($items as $item) { - [$uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp] = $item; - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $userAgent, $userAgentReferer, $userAgentIp); + [$uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp] = $item; + $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); $contactPersonRepository->save($contactPerson); if ($contactPerson->getExternalId() !== null) { $expectedContactPersons[] = $contactPerson; @@ -493,6 +505,7 @@ public static function contactPersonManyAccountsDataProvider(): Generator DemoDataGenerator::getMobilePhone(), CarbonImmutable::now(), null, + null, DemoDataGenerator::getUserAgent(), 'https://bitrix24.com/apps/store?utm_source=bx24', DemoDataGenerator::getUserAgentIp() @@ -511,6 +524,7 @@ public static function contactPersonManyAccountsDataProvider(): Generator DemoDataGenerator::getMobilePhone(), null, $externalId, + null, DemoDataGenerator::getUserAgent(), 'https://bitrix24.com/apps/store?utm_source=bx24', DemoDataGenerator::getUserAgentIp() @@ -529,6 +543,7 @@ public static function contactPersonManyAccountsDataProvider(): Generator DemoDataGenerator::getMobilePhone(), null, $externalId, + null, DemoDataGenerator::getUserAgent(), 'https://bitrix24.com/apps/store?utm_source=bx24', DemoDataGenerator::getUserAgentIp() @@ -555,6 +570,7 @@ public static function contactPersonDataProvider(): Generator DemoDataGenerator::getMobilePhone(), CarbonImmutable::now(), null, + null, DemoDataGenerator::getUserAgent(), 'https://bitrix24.com/apps/store?utm_source=bx24', DemoDataGenerator::getUserAgentIp() @@ -579,6 +595,7 @@ public static function contactPersonWithDifferentStatusesDataProvider(): Generat DemoDataGenerator::getMobilePhone(), CarbonImmutable::now(), null, + null, DemoDataGenerator::getUserAgent(), 'https://bitrix24.com/apps/store?utm_source=bx24', DemoDataGenerator::getUserAgentIp() @@ -598,6 +615,7 @@ public static function contactPersonWithDifferentStatusesDataProvider(): Generat DemoDataGenerator::getMobilePhone(), CarbonImmutable::now(), null, + null, DemoDataGenerator::getUserAgent(), 'https://bitrix24.com/apps/store?utm_source=bx24', DemoDataGenerator::getUserAgentIp() @@ -617,6 +635,7 @@ public static function contactPersonWithDifferentStatusesDataProvider(): Generat DemoDataGenerator::getMobilePhone(), CarbonImmutable::now(), null, + null, DemoDataGenerator::getUserAgent(), 'https://bitrix24.com/apps/store?utm_source=bx24', DemoDataGenerator::getUserAgentIp() diff --git a/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceReferenceImplementationTest.php b/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceReferenceImplementationTest.php index f1abf918..7b81847e 100644 --- a/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceReferenceImplementationTest.php +++ b/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceReferenceImplementationTest.php @@ -30,6 +30,7 @@ protected function createContactPersonImplementation( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp @@ -49,6 +50,7 @@ protected function createContactPersonImplementation( $phoneNumber, $mobilePhoneVerifiedAt, $externalId, + $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp diff --git a/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonReferenceEntityImplementation.php b/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonReferenceEntityImplementation.php index 33799a2a..869538b7 100644 --- a/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonReferenceEntityImplementation.php +++ b/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonReferenceEntityImplementation.php @@ -32,6 +32,7 @@ public function __construct( private ?PhoneNumber $mobilePhone, private ?CarbonImmutable $mobilePhoneVerifiedAt, private ?string $externalId, + private readonly ?int $bitrix24UserId, private readonly ?string $userAgent, private readonly ?string $userAgentReferer, private readonly ?IP $userAgentIp @@ -182,6 +183,11 @@ public function getExternalId(): ?string return $this->externalId; } + public function getBitrix24UserId(): ?int + { + return $this->bitrix24UserId; + } + public function getUserAgent(): ?string { return $this->userAgent; diff --git a/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementationTest.php b/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementationTest.php index b69c64a4..630fc1d6 100644 --- a/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementationTest.php +++ b/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementationTest.php @@ -67,6 +67,7 @@ protected function createContactPersonImplementation( ?PhoneNumber $phoneNumber, ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, + ?int $bitrix24UserId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp @@ -86,6 +87,7 @@ protected function createContactPersonImplementation( $phoneNumber, $mobilePhoneVerifiedAt, $externalId, + $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp From e4ec9ba53733e0ed5b6eecd21bc27e0c6173b63b Mon Sep 17 00:00:00 2001 From: mesilov Date: Thu, 25 Jul 2024 01:38:22 +0600 Subject: [PATCH 110/138] Add application installation status handling Implemented detailed application installation status management in the `ApplicationInstallationInterface` with corresponding methods. Introduced `ApplicationInstallationStatus` enum to define possible states. Included updates to contact person handling and external ID management. Signed-off-by: mesilov --- .../Docs/ApplicationInstallations.md | 14 ++- .../ApplicationInstallationInterface.php | 96 ++++++++++++++++--- .../Entity/ApplicationInstallationStatus.php | 13 +++ ...yContactPersonRepositoryImplementation.php | 1 + 4 files changed, 108 insertions(+), 16 deletions(-) create mode 100644 src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationStatus.php diff --git a/src/Application/Contracts/ApplicationInstallations/Docs/ApplicationInstallations.md b/src/Application/Contracts/ApplicationInstallations/Docs/ApplicationInstallations.md index 2efc0228..f9349fcb 100644 --- a/src/Application/Contracts/ApplicationInstallations/Docs/ApplicationInstallations.md +++ b/src/Application/Contracts/ApplicationInstallations/Docs/ApplicationInstallations.md @@ -1,15 +1,25 @@ - Install Start + - add ?contact person - add b24 Account - add / find b24 partner - add new installation in mode new Install Finish -- b24 account mark as active + +- b24 account mark as active - installation mark as active +Application Active + +- change contact person +- change bitrix24 partner contact person +- change bitrix24 partner +- change bitrix24 licence +- change bitrix24 application status + Uninstall + - ?delete contact person - delete b24 account - mark installation as deleted \ No newline at end of file diff --git a/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterface.php b/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterface.php index 9599a314..ef929581 100644 --- a/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterface.php +++ b/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterface.php @@ -4,11 +4,8 @@ namespace Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Entity; -use Bitrix24\SDK\Application\Contracts\Bitrix24Accounts\Entity\Bitrix24AccountStatus; -use Bitrix24\SDK\Core\Credentials\AuthToken; -use Bitrix24\SDK\Core\Credentials\Scope; +use Bitrix24\SDK\Application\ApplicationStatus; use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; -use Bitrix24\SDK\Core\Response\DTO\RenewedAuthToken; use Carbon\CarbonImmutable; use Symfony\Component\Uid\Uuid; @@ -39,29 +36,100 @@ public function getBitrix24AccountId(): Uuid; */ public function getContactPersonId(): ?Uuid; + /** + * Change contact person + */ + public function changeContactPerson(?Uuid $uuid): void; + + /** + * @return Uuid|null get bitrix24 partner contact person id related with this installation, optional + */ + public function getBitrix24PartnerContactPersonId(): ?Uuid; + + /** + * Change bitrix24 partner contact person + */ + public function changeBitrix24PartnerContactPerson(?Uuid $uuid): void; + /** * @return Uuid|null get Bitrix24 Partner id related with this installation, optional */ public function getBitrix24PartnerId(): ?Uuid; /** - * @return mixed - * - new - * - active - * - blocked - * - uninstalled + * Change bitrix24 partner */ - public function getInstallationStatus(); + public function changeBitrix24Partner(?Uuid $uuid): void; /** - * @return string|null application instalation projection in crm /erp - lead or deal id + * Get external id for application installation projection in crm / erp - lead or deal id + * @return string|null application installation projection in crm / erp - lead or deal id */ public function getExternalId(): ?string; - // get application status + /** + * set external id for application installation projection in crm / erp - lead or deal id + */ + public function setExternalId(?string $externalId): void; + + /** + * Get application installation status + * + * @return ApplicationInstallationStatus + */ + public function getStatus(): ApplicationInstallationStatus; + + /** + * Finish application installation + */ + public function applicationInstalled(): void; + + /** + * Application uninstalled + */ + public function applicationUninstalled(): void; + + /** + * Change status to active + * @param non-empty-string|null $comment + * @throws InvalidArgumentException + */ + public function markAsActive(?string $comment): void; - // get tariff code + /** + * Change status to blocked + * @param non-empty-string|null $comment + * @throws InvalidArgumentException + */ + public function markAsBlocked(?string $comment): void; - // get subscription mode? + /** + * Get application status + */ + public function getApplicationStatus(): ApplicationStatus; + /** + * Change application status + * @link https://training.bitrix24.com/rest_help/general/app_info.php + */ + public function changeApplicationStatus(ApplicationStatus $applicationStatus): void; + + /** + * Get plan designation without specified region. + * + * @link https://training.bitrix24.com/rest_help/general/app_info.php + */ + public function getBitrix24LicenseFamily(): string; + + /** + * Change plan designation without specified region. + * + * @link https://training.bitrix24.com/rest_help/general/app_info.php + */ + public function changeBitrix24LicenseFamily(string $licenseCode): 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..66f6d43f --- /dev/null +++ b/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationStatus.php @@ -0,0 +1,13 @@ +getStatus()) { continue; } + if ($externalId === $item->getExternalId()) { $result[] = $item; } From 5225c39a961dffad4297469545c96eaf71f15260 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 27 Jul 2024 01:29:03 +0600 Subject: [PATCH 111/138] Add Bitrix24 partner ID handling to contact persons Introduced the ability to set and get the Bitrix24 partner ID for contact persons. Updated tests and documentation to support this new functionality, ensuring comprehensive test coverage and proper documentation. Signed-off-by: mesilov --- .../ContactPersons/Docs/ContactPersons.md | 4 + .../Entity/ContactPersonInterface.php | 10 + src/Application/PortalLicenseFamily.php | 19 ++ .../Entity/ContactPersonInterfaceTest.php | 173 +++++++++++++++--- .../ContactPersonRepositoryInterfaceTest.php | 52 ++++-- 5 files changed, 214 insertions(+), 44 deletions(-) create mode 100644 src/Application/PortalLicenseFamily.php diff --git a/src/Application/Contracts/ContactPersons/Docs/ContactPersons.md b/src/Application/Contracts/ContactPersons/Docs/ContactPersons.md index f4c06ea1..d2e4461a 100644 --- a/src/Application/Contracts/ContactPersons/Docs/ContactPersons.md +++ b/src/Application/Contracts/ContactPersons/Docs/ContactPersons.md @@ -25,6 +25,8 @@ Store information about person who installed application | `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 | - | @@ -54,6 +56,8 @@ stateDiagram-v2 - 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;` diff --git a/src/Application/Contracts/ContactPersons/Entity/ContactPersonInterface.php b/src/Application/Contracts/ContactPersons/Entity/ContactPersonInterface.php index 804ef5b4..a2a7c7c3 100644 --- a/src/Application/Contracts/ContactPersons/Entity/ContactPersonInterface.php +++ b/src/Application/Contracts/ContactPersons/Entity/ContactPersonInterface.php @@ -114,6 +114,16 @@ public function getExternalId(): ?string; */ 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 */ diff --git a/src/Application/PortalLicenseFamily.php b/src/Application/PortalLicenseFamily.php new file mode 100644 index 00000000..cd286022 --- /dev/null +++ b/src/Application/PortalLicenseFamily.php @@ -0,0 +1,19 @@ +createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $phoneNumber, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); + $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()); } @@ -88,12 +90,13 @@ final public function testGetStatus( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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()); } @@ -115,12 +118,13 @@ final public function testMarkAsActive( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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'; @@ -147,12 +151,13 @@ final public function testMarkAsBlocked( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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()); @@ -177,12 +182,13 @@ final public function testMarkAsDeleted( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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()); @@ -207,12 +213,13 @@ final public function testMarkAsDeletedBlockedAccount( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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()); @@ -241,12 +248,13 @@ final public function testMarkAsDeletedDeletedAccount( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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); @@ -271,12 +279,13 @@ final public function testGetFullName( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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()); } @@ -298,12 +307,13 @@ final public function testChangeFullName( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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()); @@ -327,12 +337,13 @@ final public function testGetUpdatedAt( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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()); @@ -356,12 +367,13 @@ final public function testCreatedAt( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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()); } @@ -383,12 +395,13 @@ final public function testGetEmail( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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()); } @@ -410,12 +423,13 @@ final public function testChangeEmail( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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); @@ -455,12 +469,13 @@ final public function testMarkEmailAsVerified( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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 @@ -489,12 +504,13 @@ final public function testGetMobilePhone( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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()); } @@ -516,12 +532,13 @@ final public function testChangeMobilePhone( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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); @@ -554,12 +571,13 @@ final public function testGetMobilePhoneVerifiedAt( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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(); @@ -585,12 +603,13 @@ final public function testMarkMobilePhoneAsVerified( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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(); @@ -618,12 +637,13 @@ final public function testGetComment( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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()); @@ -647,12 +667,13 @@ final public function testSetExternalId( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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()); @@ -677,18 +698,19 @@ final public function testGetExternalId( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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, $userAgent, $userAgentReferer, $userAgentIp); + $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()); } @@ -710,20 +732,93 @@ final public function testGetBitrix24UserId( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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, $userAgent, $userAgentReferer, $userAgentIp); + $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')] @@ -742,12 +837,13 @@ final public function testGetUserAgent( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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()); } @@ -769,12 +865,13 @@ final public function testGetUserAgentReferer( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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()); } @@ -796,12 +893,13 @@ final public function testGetUserAgentIp( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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()); } @@ -824,6 +922,27 @@ public static function contactPersonDataProvider(): Generator 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() diff --git a/tests/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php b/tests/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php index 2cff13a6..f255af7f 100644 --- a/tests/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php +++ b/tests/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php @@ -39,6 +39,7 @@ abstract protected function createContactPersonImplementation( ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp @@ -67,13 +68,14 @@ final public function testSave( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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()); @@ -102,13 +104,14 @@ final public function testDelete( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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()); @@ -141,14 +144,14 @@ final public function testDeleteWithUnsavedElement( ?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, $userAgent, $userAgentReferer, $userAgentIp); - + $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()); } @@ -174,13 +177,14 @@ final public function testGetById( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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()); @@ -205,6 +209,7 @@ final public function testGetByIdWithNonExist( ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp @@ -234,13 +239,14 @@ final public function testFindByEmailWithHappyPath( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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); @@ -265,13 +271,14 @@ final public function testFindByEmailWithNonExistsEmail( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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'); @@ -296,13 +303,14 @@ final public function testFindByEmailWithDifferentStatuses( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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); @@ -317,8 +325,8 @@ 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, $userAgent, $userAgentReferer, $userAgentIp] = $item; - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); + [$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; @@ -339,8 +347,8 @@ 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, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp] = $item; - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); + [$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; @@ -374,13 +382,14 @@ final public function testFindByExternalId( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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()); @@ -411,13 +420,14 @@ final public function testFindByExternalIdWithNonExistsId( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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())); @@ -444,13 +454,14 @@ final public function testFindByExternalIdWithEmptyId( ?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, $userAgent, $userAgentReferer, $userAgentIp); + $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); @@ -467,8 +478,8 @@ final public function testFindByExternalIdWithMultipleInstalls(array $items): vo $expectedContactPersons = []; $expectedExternalId = null; foreach ($items as $item) { - [$uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp] = $item; - $contactPerson = $this->createContactPersonImplementation($uuid, $createdAt, $updatedAt, $contactPersonStatus, $name, $surname, $patronymic, $email, $emailVerifiedAt, $comment, $mobilePhone, $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, $userAgent, $userAgentReferer, $userAgentIp); + [$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; @@ -506,6 +517,7 @@ public static function contactPersonManyAccountsDataProvider(): Generator CarbonImmutable::now(), null, null, + null, DemoDataGenerator::getUserAgent(), 'https://bitrix24.com/apps/store?utm_source=bx24', DemoDataGenerator::getUserAgentIp() @@ -525,6 +537,7 @@ public static function contactPersonManyAccountsDataProvider(): Generator null, $externalId, null, + null, DemoDataGenerator::getUserAgent(), 'https://bitrix24.com/apps/store?utm_source=bx24', DemoDataGenerator::getUserAgentIp() @@ -544,6 +557,7 @@ public static function contactPersonManyAccountsDataProvider(): Generator null, $externalId, null, + null, DemoDataGenerator::getUserAgent(), 'https://bitrix24.com/apps/store?utm_source=bx24', DemoDataGenerator::getUserAgentIp() @@ -571,6 +585,7 @@ public static function contactPersonDataProvider(): Generator CarbonImmutable::now(), null, null, + null, DemoDataGenerator::getUserAgent(), 'https://bitrix24.com/apps/store?utm_source=bx24', DemoDataGenerator::getUserAgentIp() @@ -596,6 +611,7 @@ public static function contactPersonWithDifferentStatusesDataProvider(): Generat CarbonImmutable::now(), null, null, + null, DemoDataGenerator::getUserAgent(), 'https://bitrix24.com/apps/store?utm_source=bx24', DemoDataGenerator::getUserAgentIp() @@ -616,6 +632,7 @@ public static function contactPersonWithDifferentStatusesDataProvider(): Generat CarbonImmutable::now(), null, null, + null, DemoDataGenerator::getUserAgent(), 'https://bitrix24.com/apps/store?utm_source=bx24', DemoDataGenerator::getUserAgentIp() @@ -636,6 +653,7 @@ public static function contactPersonWithDifferentStatusesDataProvider(): Generat CarbonImmutable::now(), null, null, + null, DemoDataGenerator::getUserAgent(), 'https://bitrix24.com/apps/store?utm_source=bx24', DemoDataGenerator::getUserAgentIp() From 002cb45fa304910d80b4f6eba5018c0d5fc2735b Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 27 Jul 2024 01:35:27 +0600 Subject: [PATCH 112/138] Add bitrix24PartnerId/Uuid to ContactPerson entities Extended the ContactPerson entities and their respective tests to include the bitrix24PartnerId/UUid field. This change ensures that we can store and retrieve Bitrix24 partner UUIDs for contact persons, enhancing our data handling capabilities. Signed-off-by: mesilov --- ...tactPersonInterfaceReferenceImplementationTest.php | 2 ++ .../ContactPersonReferenceEntityImplementation.php | 11 +++++++++++ ...emoryContactPersonRepositoryImplementationTest.php | 2 ++ 3 files changed, 15 insertions(+) diff --git a/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceReferenceImplementationTest.php b/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceReferenceImplementationTest.php index 7b81847e..3f3f70d0 100644 --- a/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceReferenceImplementationTest.php +++ b/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceReferenceImplementationTest.php @@ -31,6 +31,7 @@ protected function createContactPersonImplementation( ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerUuid, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp @@ -51,6 +52,7 @@ protected function createContactPersonImplementation( $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, + $bitrix24PartnerUuid, $userAgent, $userAgentReferer, $userAgentIp diff --git a/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonReferenceEntityImplementation.php b/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonReferenceEntityImplementation.php index 869538b7..411efed6 100644 --- a/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonReferenceEntityImplementation.php +++ b/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonReferenceEntityImplementation.php @@ -33,6 +33,7 @@ public function __construct( 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 @@ -188,6 +189,16 @@ 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; diff --git a/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementationTest.php b/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementationTest.php index 630fc1d6..7a9987c5 100644 --- a/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementationTest.php +++ b/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementationTest.php @@ -68,6 +68,7 @@ protected function createContactPersonImplementation( ?CarbonImmutable $mobilePhoneVerifiedAt, ?string $externalId, ?int $bitrix24UserId, + ?Uuid $bitrix24PartnerId, ?string $userAgent, ?string $userAgentReferer, ?IP $userAgentIp @@ -88,6 +89,7 @@ protected function createContactPersonImplementation( $mobilePhoneVerifiedAt, $externalId, $bitrix24UserId, + $bitrix24PartnerId, $userAgent, $userAgentReferer, $userAgentIp From 072522b38f073fe3fd93a0b402747a4fec88ee69 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 27 Jul 2024 20:35:27 +0600 Subject: [PATCH 113/138] Add ApplicationInstallation reference entity implementation Implemented ApplicationInstallationReferenceEntityImplementation for testing ApplicationInstallationInterface. Updated ApplicationInstallationInterface with new methods for managing portal license family and users count. Added tests to validate the new implementation and methods. Signed-off-by: mesilov --- .../ApplicationInstallationInterface.php | 19 +- .../ApplicationInstallationInterfaceTest.php | 78 ++++++++ ...tallationReferenceEntityImplementation.php | 172 ++++++++++++++++++ ...24AccountReferenceEntityImplementation.php | 22 +-- 4 files changed, 278 insertions(+), 13 deletions(-) create mode 100644 tests/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceTest.php create mode 100644 tests/Unit/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationReferenceEntityImplementation.php diff --git a/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterface.php b/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterface.php index ef929581..c58ffc7d 100644 --- a/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterface.php +++ b/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterface.php @@ -5,6 +5,7 @@ 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; @@ -119,14 +120,28 @@ public function changeApplicationStatus(ApplicationStatus $applicationStatus): v * * @link https://training.bitrix24.com/rest_help/general/app_info.php */ - public function getBitrix24LicenseFamily(): string; + public function getPortalLicenseFamily(): PortalLicenseFamily; /** * Change plan designation without specified region. * * @link https://training.bitrix24.com/rest_help/general/app_info.php */ - public function changeBitrix24LicenseFamily(string $licenseCode): void; + public function changePortalLicenseFamily(PortalLicenseFamily $portalLicenseFamily): void; + + /** + * Get bitrix24 portal users count + * @return int|null + */ + public function getPortalUsersCount(): ?int; + + /** + * Change bitrix24 portal users count + * + * @param int $usersCount + * @return void + */ + public function changePortalUsersCount(int $usersCount): void; /** * Get comment diff --git a/tests/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceTest.php b/tests/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceTest.php new file mode 100644 index 00000000..40f3a413 --- /dev/null +++ b/tests/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceTest.php @@ -0,0 +1,78 @@ +createApplicationInstallationImplementation($uuid, $applicationInstallationStatus, $createdAt, $updatedAt, $bitrix24AccountUuid, $applicationStatus, $portalLicenseFamily, $portalUsersCount, $clientContactPersonUuid, $partnerContactPersonUuid, $partnerUuid, $externalId); + $this->assertEquals($uuid, $installation->getId()); + } + + public static function applicationInstallationDataProvider(): Generator + { + yield 'status-new-all-fields' => [ + Uuid::v7(), + ApplicationInstallationStatus::new, // application installation status + CarbonImmutable::now(), // created at + CarbonImmutable::now(), // updated at + Uuid::v7(), // bitrix24 account id + Uuid::v7(), // ?client contact person id + Uuid::v7(), // ?partner contact person id + Uuid::v7(), // ?partner id + null, // external id + ApplicationStatus::subscription(), // application status from bitrix24 api call response + PortalLicenseFamily::nfr, // portal license family value + null, // bitrix24 portal users count + null, // comment + ]; + } +} \ 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..fba8703b --- /dev/null +++ b/tests/Unit/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationReferenceEntityImplementation.php @@ -0,0 +1,172 @@ +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 + { + $this->externalId = $externalId; + $this->updatedAt = new CarbonImmutable(); + } + + public function applicationInstalled(): void + { + $this->applicationInstallationStatus = ApplicationInstallationStatus::active; + $this->updatedAt = new CarbonImmutable(); + } + + public function applicationUninstalled(): void + { + $this->applicationInstallationStatus = ApplicationInstallationStatus::deleted; + $this->updatedAt = new CarbonImmutable(); + } + + public function markAsActive(?string $comment): void + { + $this->applicationInstallationStatus = ApplicationInstallationStatus::active; + $this->comment = $comment; + $this->updatedAt = new CarbonImmutable(); + } + + public function markAsBlocked(?string $comment): void + { + $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/Bitrix24Accounts/Entity/Bitrix24AccountReferenceEntityImplementation.php b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountReferenceEntityImplementation.php index ce763563..84afef59 100644 --- a/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountReferenceEntityImplementation.php +++ b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountReferenceEntityImplementation.php @@ -35,17 +35,17 @@ final class Bitrix24AccountReferenceEntityImplementation implements Bitrix24Acco 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, + 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(); From a90c5b837cbb7323694627720c6f7c0cf07b964b Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 28 Jul 2024 02:26:17 +0600 Subject: [PATCH 114/138] Add validation and update tests for application status Introduce validation logic to check the status before changing application installation status to active or deleted. Also, added extensive unit tests to cover these new behaviors for better reliability and clarity. Signed-off-by: mesilov --- .../Docs/ApplicationInstallations.md | 9 +- .../ApplicationInstallationInterface.php | 47 ++- .../ApplicationInstallationInterfaceTest.php | 341 +++++++++++++++++- ...onInterfaceReferenceImplementationTest.php | 55 +++ ...tallationReferenceEntityImplementation.php | 23 +- 5 files changed, 459 insertions(+), 16 deletions(-) create mode 100644 tests/Unit/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceReferenceImplementationTest.php diff --git a/src/Application/Contracts/ApplicationInstallations/Docs/ApplicationInstallations.md b/src/Application/Contracts/ApplicationInstallations/Docs/ApplicationInstallations.md index f9349fcb..6eb0e7b8 100644 --- a/src/Application/Contracts/ApplicationInstallations/Docs/ApplicationInstallations.md +++ b/src/Application/Contracts/ApplicationInstallations/Docs/ApplicationInstallations.md @@ -15,11 +15,16 @@ Application Active - change contact person - change bitrix24 partner contact person - change bitrix24 partner -- change bitrix24 licence +- change bitrix24 licence family - change bitrix24 application status Uninstall - ?delete contact person - delete b24 account -- mark installation as deleted \ No newline at end of file +- mark installation as deleted + +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 index c58ffc7d..fd5c4ad1 100644 --- a/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterface.php +++ b/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterface.php @@ -28,27 +28,41 @@ public function getCreatedAt(): CarbonImmutable; public function getUpdatedAt(): CarbonImmutable; /** - * @return Uuid get Bitrix24 Account id related with this installation + * 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; /** - * @return Uuid|null get contact person id related with this installation, optional + * 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; /** - * @return Uuid|null get bitrix24 partner contact person id related with this installation, optional + * 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; @@ -59,39 +73,56 @@ 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 projection in crm / erp - lead or deal id - * @return string|null application installation projection in crm / erp - lead or deal id + * 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; /** - * set external id for application installation projection in crm / erp - lead or deal id + * Get external id for application installation + * + * Set external id for application installation related entity in crm or erp - lead or deal id */ public function setExternalId(?string $externalId): void; /** * Get application installation status * - * @return ApplicationInstallationStatus + * new - started the installation procedure, but have not yet finalized, there is no “installation completed” + * active - installation procedure 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 + * Change status to active for blocked accounts + * * @param non-empty-string|null $comment * @throws InvalidArgumentException */ diff --git a/tests/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceTest.php b/tests/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceTest.php index 40f3a413..3744842c 100644 --- a/tests/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceTest.php +++ b/tests/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceTest.php @@ -8,7 +8,10 @@ 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; @@ -50,29 +53,357 @@ final public function testGetId( ?Uuid $clientContactPersonUuid, ?Uuid $partnerContactPersonUuid, ?Uuid $partnerUuid, - ?string $externalId, + ?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()); + } + + #[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()); + } + + #[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(); + } + public static function applicationInstallationDataProvider(): Generator { yield 'status-new-all-fields' => [ - Uuid::v7(), + Uuid::v7(), // uuid ApplicationInstallationStatus::new, // application installation status CarbonImmutable::now(), // created at - CarbonImmutable::now(), // updated 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 - null, // external 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, // comment + 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/Unit/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceReferenceImplementationTest.php b/tests/Unit/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceReferenceImplementationTest.php new file mode 100644 index 00000000..e7f8a3d4 --- /dev/null +++ b/tests/Unit/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceReferenceImplementationTest.php @@ -0,0 +1,55 @@ +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», сurrent status «%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», сurrent status «%s»', + ApplicationInstallationStatus::active->name, + ApplicationInstallationStatus::blocked->name, + $this->applicationInstallationStatus->name + )); + } $this->applicationInstallationStatus = ApplicationInstallationStatus::deleted; $this->updatedAt = new CarbonImmutable(); } From 6ac7071dcf2ea3382d3436ff3f60626c9f32662e Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 28 Jul 2024 12:34:26 +0600 Subject: [PATCH 115/138] Implement stricter status checks and extend test coverage Added precondition checks for application status changes. Enhanced documentation for clarity in interface methods with new constraints. Comprehensive tests for `markAsActive`, `markAsBlocked`, and other status-related methods were introduced to ensure correct behavior. Signed-off-by: mesilov --- .../ApplicationInstallationInterface.php | 26 +- .../ApplicationInstallationInterfaceTest.php | 234 ++++++++++++++++++ ...tallationReferenceEntityImplementation.php | 19 +- 3 files changed, 273 insertions(+), 6 deletions(-) diff --git a/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterface.php b/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterface.php index fd5c4ad1..f4437b07 100644 --- a/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterface.php +++ b/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterface.php @@ -96,7 +96,7 @@ 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 procedure finished, active portal, there is a connection to B24 + * 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 */ @@ -121,7 +121,9 @@ public function applicationInstalled(): void; public function applicationUninstalled(): void; /** - * Change status to active for blocked accounts + * Change status to active for blocked application installation accounts + * + * You can activate accounts only blocked state * * @param non-empty-string|null $comment * @throws InvalidArgumentException @@ -129,7 +131,10 @@ public function applicationUninstalled(): void; public function markAsActive(?string $comment): void; /** - * Change status to blocked + * 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 */ @@ -137,18 +142,26 @@ 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 plan designation without specified region. + * 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; @@ -156,12 +169,16 @@ 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 * @return int|null */ public function getPortalUsersCount(): ?int; @@ -169,6 +186,7 @@ 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 * @param int $usersCount * @return void */ diff --git a/tests/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceTest.php b/tests/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceTest.php index 3744842c..f86eb635 100644 --- a/tests/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceTest.php +++ b/tests/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceTest.php @@ -375,6 +375,240 @@ final public function testApplicationUninstalled( $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' => [ diff --git a/tests/Unit/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationReferenceEntityImplementation.php b/tests/Unit/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationReferenceEntityImplementation.php index f69d7e54..28079f9e 100644 --- a/tests/Unit/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationReferenceEntityImplementation.php +++ b/tests/Unit/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationReferenceEntityImplementation.php @@ -141,7 +141,7 @@ public function setExternalId(?string $externalId): void public function applicationInstalled(): void { if ($this->applicationInstallationStatus !== ApplicationInstallationStatus::new) { - throw new InvalidArgumentException(sprintf('application installation must be in status «%s», сurrent status «%s»', + throw new InvalidArgumentException(sprintf('application installation must be in status «%s», current state «%s»', ApplicationInstallationStatus::new->name, $this->applicationInstallationStatus->name )); @@ -156,7 +156,7 @@ public function applicationInstalled(): void 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», сurrent status «%s»', + 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 @@ -168,6 +168,13 @@ public function applicationUninstalled(): void 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(); @@ -175,6 +182,14 @@ public function markAsActive(?string $comment): void 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(); From f837d4c6334c6ee610ea3842faafb82f79cc34f3 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 28 Jul 2024 18:23:58 +0600 Subject: [PATCH 116/138] Add validation and repository interface for installations Initialize 'comment' to null, validate 'externalId' input, and introduce ApplicationInstallationRepositoryInterface for persistence operations. Added new exception handling for application installation not found scenarios. Includes in-memory repository implementation and associated tests. Signed-off-by: mesilov --- .../ApplicationInstallationInterface.php | 5 +- ...plicationInstallationNotFoundException.php | 11 +++ ...icationInstallationRepositoryInterface.php | 51 ++++++++++ .../ApplicationInstallationInterfaceTest.php | 9 ++ ...onInstallationRepositoryImplementation.php | 97 +++++++++++++++++++ ...tallationReferenceEntityImplementation.php | 8 +- 6 files changed, 177 insertions(+), 4 deletions(-) create mode 100644 src/Application/Contracts/ApplicationInstallations/Exceptions/ApplicationInstallationNotFoundException.php create mode 100644 src/Application/Contracts/ApplicationInstallations/Repository/ApplicationInstallationRepositoryInterface.php create mode 100644 tests/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementation.php diff --git a/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterface.php b/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterface.php index f4437b07..4e89f926 100644 --- a/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterface.php +++ b/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterface.php @@ -89,6 +89,8 @@ 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; @@ -179,7 +181,6 @@ public function changePortalLicenseFamily(PortalLicenseFamily $portalLicenseFami * * Return bitrix24 portal users count stored in persistence storage * This method do not call bitrix24 rest api to get actual data - * @return int|null */ public function getPortalUsersCount(): ?int; @@ -187,8 +188,6 @@ 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 - * @param int $usersCount - * @return void */ public function changePortalUsersCount(int $usersCount): void; diff --git a/src/Application/Contracts/ApplicationInstallations/Exceptions/ApplicationInstallationNotFoundException.php b/src/Application/Contracts/ApplicationInstallations/Exceptions/ApplicationInstallationNotFoundException.php new file mode 100644 index 00000000..99e3b6a0 --- /dev/null +++ b/src/Application/Contracts/ApplicationInstallations/Exceptions/ApplicationInstallationNotFoundException.php @@ -0,0 +1,11 @@ +assertEquals($externalId, $installation->getExternalId()); } + /** + * @throws InvalidArgumentException + */ #[Test] #[DataProvider('applicationInstallationDataProvider')] #[TestDox('test setExternalId method')] @@ -293,6 +296,12 @@ final public function testSetExternalId( $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] diff --git a/tests/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementation.php b/tests/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementation.php new file mode 100644 index 00000000..5d6a6dc6 --- /dev/null +++ b/tests/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementation.php @@ -0,0 +1,97 @@ +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 $bitrix24AccountId): array + { + $this->logger->debug('InMemoryApplicationInstallationRepositoryImplementation.findByBitrix24AccountId', ['id' => $bitrix24AccountId->toRfc4122()]); + + $result = []; + foreach ($this->items as $item) { + if ($item->getBitrix24AccountId() === $bitrix24AccountId) { + $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/Entity/ApplicationInstallationReferenceEntityImplementation.php b/tests/Unit/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationReferenceEntityImplementation.php index 28079f9e..3bb4165e 100644 --- a/tests/Unit/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationReferenceEntityImplementation.php +++ b/tests/Unit/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationReferenceEntityImplementation.php @@ -20,7 +20,7 @@ */ final class ApplicationInstallationReferenceEntityImplementation implements ApplicationInstallationInterface { - private ?string $comment; + private ?string $comment = null; public function __construct( private readonly Uuid $id, @@ -131,6 +131,10 @@ public function getExternalId(): ?string 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(); } @@ -146,6 +150,7 @@ public function applicationInstalled(): void $this->applicationInstallationStatus->name )); } + $this->applicationInstallationStatus = ApplicationInstallationStatus::active; $this->updatedAt = new CarbonImmutable(); } @@ -162,6 +167,7 @@ public function applicationUninstalled(): void $this->applicationInstallationStatus->name )); } + $this->applicationInstallationStatus = ApplicationInstallationStatus::deleted; $this->updatedAt = new CarbonImmutable(); } From 9abee5e9a9d57783148a2a7bff68f9d447e9068e Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 29 Jul 2024 02:01:40 +0600 Subject: [PATCH 117/138] Add repository interface and tests for installations Added a new method `getById` to `ApplicationInstallationRepositoryInterface`. Renamed the test path prefix to `Unit`. Included various new tests for application installations, updating and reorganizing the existing structure. Signed-off-by: mesilov --- .../Docs/ApplicationInstallations.md | 144 ++++++- ...tallationApplicationStatusChangedEvent.php | 20 + ...nstallationBitrix24PartnerChangedEvent.php | 20 + ...trix24PartnerContactPersonChangedEvent.php | 20 + .../ApplicationInstallationBlockedEvent.php | 19 + ...nInstallationContactPersonChangedEvent.php | 20 + .../ApplicationInstallationCreatedEvent.php | 19 + ...tionInstallationExternalIdChangedEvent.php | 20 + .../ApplicationInstallationFinishedEvent.php | 24 ++ ...llationPortalLicenseFamilyChangedEvent.php | 21 ++ ...stallationPortalUsersCountChangedEvent.php | 20 + .../ApplicationInstallationUnblockedEvent.php | 19 + ...pplicationInstallationUninstalledEvent.php | 23 ++ ...icationInstallationRepositoryInterface.php | 12 +- ...ionInstallationRepositoryInterfaceTest.php | 354 ++++++++++++++++++ ...onInstallationRepositoryImplementation.php | 14 +- ...stallationRepositoryImplementationTest.php | 44 +++ 17 files changed, 777 insertions(+), 36 deletions(-) create mode 100644 src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationApplicationStatusChangedEvent.php create mode 100644 src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationBitrix24PartnerChangedEvent.php create mode 100644 src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationBitrix24PartnerContactPersonChangedEvent.php create mode 100644 src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationBlockedEvent.php create mode 100644 src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationContactPersonChangedEvent.php create mode 100644 src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationCreatedEvent.php create mode 100644 src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationExternalIdChangedEvent.php create mode 100644 src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationFinishedEvent.php create mode 100644 src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationPortalLicenseFamilyChangedEvent.php create mode 100644 src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationPortalUsersCountChangedEvent.php create mode 100644 src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationUnblockedEvent.php create mode 100644 src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationUninstalledEvent.php create mode 100644 tests/Application/Contracts/ApplicationInstallations/Repository/ApplicationInstallationRepositoryInterfaceTest.php rename tests/{ => Unit}/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementation.php (81%) create mode 100644 tests/Unit/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementationTest.php diff --git a/src/Application/Contracts/ApplicationInstallations/Docs/ApplicationInstallations.md b/src/Application/Contracts/ApplicationInstallations/Docs/ApplicationInstallations.md index 6eb0e7b8..625935e9 100644 --- a/src/Application/Contracts/ApplicationInstallations/Docs/ApplicationInstallations.md +++ b/src/Application/Contracts/ApplicationInstallations/Docs/ApplicationInstallations.md @@ -1,30 +1,134 @@ -Install Start +# Application installation entity -- add ?contact person -- add b24 Account -- add / find b24 partner -- add new installation in mode new +Store information about application installation, linked with Bitrix24 Account with auth tokens. +Optional can store links to: -Install Finish +- 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 -- b24 account mark as active -- installation mark as active +| 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 Active +## Application installation state diagram -- change contact person -- change bitrix24 partner contact person -- change bitrix24 partner -- change bitrix24 licence family -- change bitrix24 application status +```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 +``` -Uninstall +## Repository methods -- ?delete contact person -- delete b24 account -- mark installation as deleted +- `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 -Background periodical tasks -- check portal license type +## 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/Events/ApplicationInstallationApplicationStatusChangedEvent.php b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationApplicationStatusChangedEvent.php new file mode 100644 index 00000000..8da8046f --- /dev/null +++ b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationApplicationStatusChangedEvent.php @@ -0,0 +1,20 @@ +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/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementation.php b/tests/Unit/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementation.php similarity index 81% rename from tests/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementation.php rename to tests/Unit/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementation.php index 5d6a6dc6..c8308294 100644 --- a/tests/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementation.php +++ b/tests/Unit/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementation.php @@ -2,22 +2,16 @@ declare(strict_types=1); -namespace Bitrix24\SDK\Tests\Application\Contracts\ApplicationInstallations\Repository; +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\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 InMemoryApplicationInstallationRepositoryImplementation implements ApplicationInstallationRepositoryInterface { /** @@ -64,13 +58,13 @@ public function getById(Uuid $uuid): ApplicationInstallationInterface return $this->items[$uuid->toRfc4122()]; } - public function findByBitrix24AccountId(Uuid $bitrix24AccountId): array + public function findByBitrix24AccountId(Uuid $uuid): array { - $this->logger->debug('InMemoryApplicationInstallationRepositoryImplementation.findByBitrix24AccountId', ['id' => $bitrix24AccountId->toRfc4122()]); + $this->logger->debug('InMemoryApplicationInstallationRepositoryImplementation.findByBitrix24AccountId', ['id' => $uuid->toRfc4122()]); $result = []; foreach ($this->items as $item) { - if ($item->getBitrix24AccountId() === $bitrix24AccountId) { + if ($item->getBitrix24AccountId() === $uuid) { $result[] = $item; } } 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..17c8e63f --- /dev/null +++ b/tests/Unit/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementationTest.php @@ -0,0 +1,44 @@ + Date: Wed, 31 Jul 2024 01:52:17 +0600 Subject: [PATCH 118/138] Add Bitrix24Partner status and interface Introduced the `Bitrix24PartnerStatus` enum to define partner statuses, and a `Bitrix24PartnerInterface` to standardize partner management operations, including partner creation, status changes, and retrieving partner information. This standardization aims to streamline interactions with Bitrix24 partner entities. Signed-off-by: mesilov --- .../Entity/Bitrix24PartnerInterface.php | 141 ++++++++++++++++++ .../Entity/Bitrix24PartnerStatus.php | 12 ++ 2 files changed, 153 insertions(+) create mode 100644 src/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterface.php create mode 100644 src/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerStatus.php diff --git a/src/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterface.php b/src/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterface.php new file mode 100644 index 00000000..257419be --- /dev/null +++ b/src/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterface.php @@ -0,0 +1,141 @@ + Date: Tue, 6 Aug 2024 23:00:20 +0600 Subject: [PATCH 119/138] Add Bitrix24 Partners Repository and Entity Implementation Introduce Bitrix24 Partner entity classes and a repository interface with in-memory implementations for testing. Added tests cover save, delete, getById, and associated functions to ensure data persistence operations work correctly. Signed-off-by: mesilov --- .../Bitrix24Partners/Docs/Bitrix24Partners.md | 108 +++ .../Entity/Bitrix24PartnerInterface.php | 30 +- .../Events/Bitrix24PartnerBlockedEvent.php | 18 + .../Events/Bitrix24PartnerCreatedEvent.php | 18 + .../Events/Bitrix24PartnerDeletedEvent.php | 18 + .../Bitrix24PartnerEmailChangedEvent.php | 20 + .../Bitrix24PartnerExternalIdChangedEvent.php | 20 + .../Bitrix24PartnerOpenLineIdChangedEvent.php | 20 + .../Bitrix24PartnerPartnerIdChangedEvent.php | 20 + .../Bitrix24PartnerPhoneChangedEvent.php | 21 + .../Bitrix24PartnerSiteChangedEvent.php | 20 + .../Bitrix24PartnerTitleChangedEvent.php | 20 + .../Events/Bitrix24PartnerUnblockedEvent.php | 18 + .../Bitrix24PartnerNotFoundException.php | 11 + .../Bitrix24PartnerRepositoryInterface.php | 63 ++ .../AggregateRootEventsEmitterInterface.php | 15 + .../Entity/Bitrix24PartnerInterfaceTest.php | 641 ++++++++++++++++++ ...Bitrix24PartnerRepositoryInterfaceTest.php | 280 ++++++++ ...erInterfaceReferenceImplementationTest.php | 45 ++ ...24PartnerReferenceEntityImplementation.php | 241 +++++++ ...itrix24PartnerRepositoryImplementation.php | 154 +++++ ...x24PartnerRepositoryImplementationTest.php | 65 ++ 22 files changed, 1860 insertions(+), 6 deletions(-) create mode 100644 src/Application/Contracts/Bitrix24Partners/Docs/Bitrix24Partners.md create mode 100644 src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerBlockedEvent.php create mode 100644 src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerCreatedEvent.php create mode 100644 src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerDeletedEvent.php create mode 100644 src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerEmailChangedEvent.php create mode 100644 src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerExternalIdChangedEvent.php create mode 100644 src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerOpenLineIdChangedEvent.php create mode 100644 src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerPartnerIdChangedEvent.php create mode 100644 src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerPhoneChangedEvent.php create mode 100644 src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerSiteChangedEvent.php create mode 100644 src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerTitleChangedEvent.php create mode 100644 src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerUnblockedEvent.php create mode 100644 src/Application/Contracts/Bitrix24Partners/Exceptions/Bitrix24PartnerNotFoundException.php create mode 100644 src/Application/Contracts/Bitrix24Partners/Repository/Bitrix24PartnerRepositoryInterface.php create mode 100644 src/Application/Contracts/Events/AggregateRootEventsEmitterInterface.php create mode 100644 tests/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterfaceTest.php create mode 100644 tests/Application/Contracts/Bitrix24Partners/Repository/Bitrix24PartnerRepositoryInterfaceTest.php create mode 100644 tests/Unit/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterfaceReferenceImplementationTest.php create mode 100644 tests/Unit/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerReferenceEntityImplementation.php create mode 100644 tests/Unit/Application/Contracts/Bitrix24Partners/Repository/InMemoryBitrix24PartnerRepositoryImplementation.php create mode 100644 tests/Unit/Application/Contracts/Bitrix24Partners/Repository/InMemoryBitrix24PartnerRepositoryImplementationTest.php 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 index 257419be..cb652fe6 100644 --- a/src/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterface.php +++ b/src/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterface.php @@ -4,9 +4,6 @@ namespace Bitrix24\SDK\Application\Contracts\Bitrix24Partners\Entity; -use Bitrix24\SDK\Application\ApplicationStatus; -use Bitrix24\SDK\Application\Contracts\ApplicationInstallations\Entity\ApplicationInstallationStatus; -use Bitrix24\SDK\Application\PortalLicenseFamily; use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; use Carbon\CarbonImmutable; use libphonenumber\PhoneNumber; @@ -74,6 +71,14 @@ public function markAsActive(?string $comment): void; */ 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 */ @@ -86,6 +91,9 @@ public function getTitle(): string; /** * Set partner title + * + * @param non-empty-string $title + * @throws InvalidArgumentException */ public function setTitle(string $title): void; @@ -96,8 +104,11 @@ public function getSite(): ?string; /** * Set partner site + * + * @param non-empty-string|null $site + * @throws InvalidArgumentException */ - public function setSite(?string $siteUrl): void; + public function setSite(?string $site): void; /** * Get partner phone @@ -107,7 +118,7 @@ public function getPhone(): ?PhoneNumber; /** * Set partner phone */ - public function setPhone(?PhoneNumber $phone): void; + public function setPhone(?PhoneNumber $phoneNumber): void; /** * Get partner email @@ -116,6 +127,9 @@ public function getEmail(): ?string; /** * Set partner email + * + * @param non-empty-string|null $email + * @throws InvalidArgumentException */ public function setEmail(?string $email): void; @@ -126,6 +140,8 @@ 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; @@ -136,6 +152,8 @@ 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); + public function setOpenLineId(?string $openLineId): void; } diff --git a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerBlockedEvent.php b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerBlockedEvent.php new file mode 100644 index 00000000..e19607fd --- /dev/null +++ b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerBlockedEvent.php @@ -0,0 +1,18 @@ +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..5136247d --- /dev/null +++ b/tests/Application/Contracts/Bitrix24Partners/Repository/Bitrix24PartnerRepositoryInterfaceTest.php @@ -0,0 +1,280 @@ +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/Unit/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterfaceReferenceImplementationTest.php b/tests/Unit/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterfaceReferenceImplementationTest.php new file mode 100644 index 00000000..03fc12f0 --- /dev/null +++ b/tests/Unit/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterfaceReferenceImplementationTest.php @@ -0,0 +1,45 @@ +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->getId(), + $this->getUpdatedAt(), + $prevExternalId, + $this->getExternalId() + ); + } + + 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..cad68394 --- /dev/null +++ b/tests/Unit/Application/Contracts/Bitrix24Partners/Repository/InMemoryBitrix24PartnerRepositoryImplementation.php @@ -0,0 +1,154 @@ +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..cc140381 --- /dev/null +++ b/tests/Unit/Application/Contracts/Bitrix24Partners/Repository/InMemoryBitrix24PartnerRepositoryImplementationTest.php @@ -0,0 +1,65 @@ + Date: Tue, 6 Aug 2024 23:03:50 +0600 Subject: [PATCH 120/138] Bump phpstan version to 1.11.7 Locking the phpstan version to 1.11.7 ensures stable and consistent builds. This change avoids potential issues from future updates to the phpstan package. Signed-off-by: mesilov --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 4b936c76..5ec8df5b 100644 --- a/composer.json +++ b/composer.json @@ -47,7 +47,7 @@ "fakerphp/faker": "^1", "monolog/monolog": "^3", "nunomaduro/phpinsights": "^2", - "phpstan/phpstan": "^1", + "phpstan/phpstan": "1.11.7", "phpunit/phpunit": "^10 || ^11", "psalm/phar": "^5", "rector/rector": "^1", From 64e757784d5e5624bc98bf2bf557e826a2eb06a7 Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 7 Aug 2024 00:58:23 +0600 Subject: [PATCH 121/138] Switch to NullLogger for InMemory repository implementations Replaced Fabric::getLogger with Psr\Log\NullLogger in multiple InMemory repository implementations for consistent logging behavior in unit tests. Adjusted test suite configuration to display warnings. Signed-off-by: mesilov --- Makefile | 2 +- ...ApplicationInstallationRepositoryImplementationTest.php | 3 ++- ...InMemoryBitrix24AccountRepositoryImplementationTest.php | 3 ++- .../Bitrix24PartnerReferenceEntityImplementation.php | 7 ++++--- .../InMemoryBitrix24PartnerRepositoryImplementation.php | 2 +- ...InMemoryBitrix24PartnerRepositoryImplementationTest.php | 3 ++- .../InMemoryContactPersonRepositoryImplementationTest.php | 3 ++- 7 files changed, 14 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index cd389856..c03dbefd 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ lint-rector-fix: vendor/bin/rector process test-unit: - vendor/bin/phpunit --testsuite unit_tests + vendor/bin/phpunit --testsuite unit_tests --display-warnings # integration tests with granularity by api-scope test-integration-scope-telephony: diff --git a/tests/Unit/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementationTest.php b/tests/Unit/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementationTest.php index 17c8e63f..be5849a3 100644 --- a/tests/Unit/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementationTest.php +++ b/tests/Unit/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementationTest.php @@ -14,6 +14,7 @@ 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)] @@ -39,6 +40,6 @@ protected function createApplicationInstallationImplementation(Uuid $uuid, Appli protected function createApplicationInstallationRepositoryImplementation(): ApplicationInstallationRepositoryInterface { - return new InMemoryApplicationInstallationRepositoryImplementation(Fabric::getLogger()); + return new InMemoryApplicationInstallationRepositoryImplementation(new NullLogger()); } } \ 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 index 771636f5..42ae95b9 100644 --- a/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementationTest.php +++ b/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementationTest.php @@ -14,6 +14,7 @@ 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)] @@ -50,6 +51,6 @@ protected function createBitrix24AccountImplementation( protected function createBitrix24AccountRepositoryImplementation(): Bitrix24AccountRepositoryInterface { - return new InMemoryBitrix24AccountRepositoryImplementation(Fabric::getLogger()); + return new InMemoryBitrix24AccountRepositoryImplementation(new NullLogger()); } } \ 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 index 36ddedf4..7bc6e4fe 100644 --- a/tests/Unit/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerReferenceEntityImplementation.php +++ b/tests/Unit/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerReferenceEntityImplementation.php @@ -30,6 +30,7 @@ final class Bitrix24PartnerReferenceEntityImplementation implements Bitrix24PartnerInterface, AggregateRootEventsEmitterInterface { private ?string $comment = null; + private array $events = []; public function __construct( @@ -76,10 +77,10 @@ public function setExternalId(?string $externalId): void $this->updatedAt = new CarbonImmutable(); $this->events[] = new Bitrix24PartnerExternalIdChangedEvent( - $this->getId(), - $this->getUpdatedAt(), + $this->id, + $this->updatedAt, $prevExternalId, - $this->getExternalId() + $this->externalId ); } diff --git a/tests/Unit/Application/Contracts/Bitrix24Partners/Repository/InMemoryBitrix24PartnerRepositoryImplementation.php b/tests/Unit/Application/Contracts/Bitrix24Partners/Repository/InMemoryBitrix24PartnerRepositoryImplementation.php index cad68394..bd5133c2 100644 --- a/tests/Unit/Application/Contracts/Bitrix24Partners/Repository/InMemoryBitrix24PartnerRepositoryImplementation.php +++ b/tests/Unit/Application/Contracts/Bitrix24Partners/Repository/InMemoryBitrix24PartnerRepositoryImplementation.php @@ -75,7 +75,7 @@ public function findByExternalId(string $externalId, ?Bitrix24PartnerStatus $bit { $this->logger->debug('b24PartnerRepository.findByExternalId', [ 'externalId' => $externalId, - 'bitrix24PartnerStatus' => $bitrix24PartnerStatus->name + 'bitrix24PartnerStatus' => $bitrix24PartnerStatus?->name ]); if (trim($externalId) === '') { diff --git a/tests/Unit/Application/Contracts/Bitrix24Partners/Repository/InMemoryBitrix24PartnerRepositoryImplementationTest.php b/tests/Unit/Application/Contracts/Bitrix24Partners/Repository/InMemoryBitrix24PartnerRepositoryImplementationTest.php index cc140381..a3d822ea 100644 --- a/tests/Unit/Application/Contracts/Bitrix24Partners/Repository/InMemoryBitrix24PartnerRepositoryImplementationTest.php +++ b/tests/Unit/Application/Contracts/Bitrix24Partners/Repository/InMemoryBitrix24PartnerRepositoryImplementationTest.php @@ -26,6 +26,7 @@ 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)] @@ -60,6 +61,6 @@ protected function createBitrix24PartnerImplementation( protected function createBitrix24PartnerRepositoryImplementation(): Bitrix24PartnerRepositoryInterface { - return new InMemoryBitrix24PartnerRepositoryImplementation(Fabric::getLogger()); + return new InMemoryBitrix24PartnerRepositoryImplementation(new NullLogger()); } } \ 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 index 7a9987c5..f0bd3836 100644 --- a/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementationTest.php +++ b/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementationTest.php @@ -19,6 +19,7 @@ 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)] @@ -98,6 +99,6 @@ protected function createContactPersonImplementation( protected function createContactPersonRepositoryImplementation(): ContactPersonRepositoryInterface { - return new InMemoryContactPersonRepositoryImplementation(Fabric::getLogger()); + return new InMemoryContactPersonRepositoryImplementation(new NullLogger()); } } \ No newline at end of file From b890fc4b0945ba398295fc619e7e0121674576e8 Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 7 Aug 2024 01:26:11 +0600 Subject: [PATCH 122/138] Enhance README with formatting and additional details Updated README for better clarity and readability by adjusting formatting and adding new sections. Improved instructions for running tests and included additional examples for application setup in Bitrix24. Signed-off-by: mesilov --- README.md | 104 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 67 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 1b68984d..c6dc69ad 100644 --- a/README.md +++ b/README.md @@ -7,13 +7,13 @@ A powerful PHP library for the Bitrix24 REST API ## Build status -| CI\CD [status](https://github.com/mesilov/bitrix24-php-sdk/actions) on `master` | +| 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 status](https://github.com/mesilov/bitrix24-php-sdk/actions/workflows/integration.yml/badge.svg)](https://github.com/mesilov/bitrix24-php-sdk/actions/workflows/integration.yml) | -Integration tests run in GitHub actions with real Bitrix24 portal +Integration tests run in GitHub actions with real Bitrix24 portal ## BITRIX24-PHP-SDK ✨FEATURES✨ @@ -23,8 +23,9 @@ Support both auth modes: - [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 + +- [x] Access Token expired +- [x] Bitrix24 portal domain url changed API - level features @@ -34,18 +35,10 @@ API - level features Performance improvements 🚀 -- 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 - - [ ] write and read in one batch package - - [ ] composite batch queries to many entities (work in progress) -- [ ] read without count flag - -Low-level tools to devs: -- [ ] Rate-limit strategy -- [ ] Retry strategy for safe methods - +- [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 @@ -67,6 +60,7 @@ Low-level tools to devs: - Reliable: - test coverage: unit, integration, contract - typical examples typical for different modes of operation and they are optimized for memory \ performance + ## Architecture ### Abstraction layers @@ -83,6 +77,7 @@ Low-level tools to devs: output: b24 response dto process: b24 entities, operate with immutable objects ``` + ## Sponsors Help bitrix24-php-sdk by [boosty.to/bitrix24-php-sdk](https://boosty.to/bitrix24-php-sdk) @@ -98,7 +93,9 @@ Help bitrix24-php-sdk by [boosty.to/bitrix24-php-sdk](https://boosty.to/bitrix24 Add `"mesilov/bitrix24-php-sdk": "2.x"` to `composer.json` of your application. Or clone repo to your project. ## Examples + ### Work with webhook + ```php declare(strict_types=1); @@ -121,17 +118,58 @@ var_dump($b24Service->getMainScope()->main()->getCurrentUserProfile()->getUserPr var_dump($b24Service->getCRMScope()->lead()->list([],[],['ID','TITLE'])->getLeads()[0]->TITLE); ``` +### 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 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 + +Call in command line + +```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 -composer phpunit-run-unit-test +make test-unit ``` ### Integration tests @@ -142,12 +180,12 @@ composer phpunit-run-unit-test For run integration test you must: -1. Create [new Bitrix24 portal](https://www.bitrix24.ru/create.php?p=255670) 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 +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 @@ -159,15 +197,10 @@ INTEGRATION_TEST_LOG_LEVEL=500 8. call in command line ```shell -composer composer phpunit-run-integration-tests -``` - -#### PHP Static Analysis Tool – phpstan - -Call in command line - -```shell - composer phpstan-analyse +make test-integration-core +make test-integration-scope-telephony +make test-integration-scope-workflows +make test-integration-scope-user ``` ## Submitting bugs and feature requests @@ -182,7 +215,8 @@ bitrix24-php-sdk is licensed under the MIT License - see the `MIT-LICENSE.txt` f 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. +See also the list of [contributors](https://github.com/mesilov/bitrix24-php-sdk/graphs/contributors) which participated +in this project. ## Need custom Bitrix24 application? @@ -190,8 +224,4 @@ mesilov.maxim@gmail.com for private consultations or dedicated support ## Documentation -[Bitrix24 API documentation - Russian](http://dev.1c-bitrix.ru/rest_help/) - [Bitrix24 API documentation - English](https://training.bitrix24.com/rest_help/) - -[Register new Bitrix24 account](https://www.bitrix24.ru/create.php?p=255670) \ No newline at end of file From 406adb6ed2c6790d71882749dd3ca5d6aa15e28f Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 11 Aug 2024 01:40:02 +0600 Subject: [PATCH 123/138] Update CHANGELOG.md for new target release date Updated the release date for version 2.0-beta.3 from July 1, 2024, to August 15, 2024. Additionally, noted the migration from `DateTimeImmutable` to `CarbonImmutable` from the Carbon library. Signed-off-by: mesilov --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dc0e01e..b4130092 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # bitrix24-php-sdk change log -## 2.0-beta.3 — 1.07.2024 +## 2.0-beta.3 — 15.08.2024 ### Added @@ -61,6 +61,7 @@ ### 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 From c4ea91f6c3038f6d56c54eb2aa3d64be7a249936 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 11 Aug 2024 23:06:23 +0600 Subject: [PATCH 124/138] Switch from DateTimeImmutable to CarbonImmutable Replace all instances of DateTimeImmutable with CarbonImmutable for improved functionality and better date manipulation capabilities. Adjusted corresponding function calls and tests to align with CarbonImmutable's interface. Signed-off-by: mesilov --- src/Core/Batch.php | 4 +- .../FilterWithoutBatchWithoutCountOrder.php | 2 +- src/Core/Response/DTO/Time.php | 62 ++++--------------- .../CRM/Common/Result/AbstractCrmItem.php | 6 +- .../Deal/Result/DealCategoryItemResult.php | 4 +- .../CRM/Item/Result/ItemItemResult.php | 14 ++--- .../Common/Result/AbstractCatalogItem.php | 7 +-- src/Services/Main/Result/ServerTimeResult.php | 14 +++-- .../Task/Result/WorkflowTaskItemResult.php | 1 - .../Result/WorkflowTemplateItemResult.php | 6 +- .../Result/WorkflowInstanceItemResult.php | 11 ++-- tests/Unit/Core/Response/DTO/TimeTest.php | 16 ++--- tests/Unit/Stubs/NullBatch.php | 8 +-- .../PerformanceBenchmarks/ListCommand.php | 8 +-- 14 files changed, 61 insertions(+), 102 deletions(-) diff --git a/src/Core/Batch.php b/src/Core/Batch.php index 04314109..acc6b378 100644 --- a/src/Core/Batch.php +++ b/src/Core/Batch.php @@ -524,7 +524,7 @@ public function getTraversableList( [ 'batchCommandItemNumber' => $queryCnt, 'nextItem' => $queryResultData->getPagination()->getNextItem(), - 'durationTime' => $queryResultData->getTime()->getDuration(), + 'durationTime' => $queryResultData->getTime()->duration, ] ); @@ -691,7 +691,7 @@ public function getTraversableListWithCount( [ 'batchCommandItemNumber' => $queryCnt, 'nextItem' => $queryResultData->getPagination()->getNextItem(), - 'durationTime' => $queryResultData->getTime()->getDuration(), + 'durationTime' => $queryResultData->getTime()->duration, ] ); // iterate items in batch query result diff --git a/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php b/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php index cdcf43d0..b5a212f3 100644 --- a/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php +++ b/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php @@ -113,7 +113,7 @@ public function getTraversableList(string $apiMethod, array $order, array $filte } $this->log->debug('FilterWithoutBatchWithoutCountOrder.step', [ - 'duration' => $resultPage->getResponseData()->getTime()->getDuration(), + 'duration' => $resultPage->getResponseData()->getTime()->duration, 'currentElementId' => $currentElementId, 'lastElementId' => $lastElementId, ]); diff --git a/src/Core/Response/DTO/Time.php b/src/Core/Response/DTO/Time.php index cfaaca27..c6a508ca 100644 --- a/src/Core/Response/DTO/Time.php +++ b/src/Core/Response/DTO/Time.php @@ -4,70 +4,30 @@ namespace Bitrix24\SDK\Core\Response\DTO; -use DateTimeImmutable; +use Carbon\CarbonImmutable; use Exception; readonly class Time { public function __construct( - private float $start, - private float $finish, - private float $duration, - private float $processing, + public float $start, + public float $finish, + public float $duration, + public float $processing, /** * @see https://training.bitrix24.com/rest_help/rest_sum/operating.php */ - private float $operating, - private DateTimeImmutable $dateStart, - private DateTimeImmutable $dateFinish, + public float $operating, + public CarbonImmutable $dateStart, + public CarbonImmutable $dateFinish, /** * @see https://training.bitrix24.com/rest_help/rest_sum/operating.php */ - private ?int $operatingResetAt + public ?int $operatingResetAt ) { } - public function getStart(): float - { - return $this->start; - } - - public function getFinish(): float - { - return $this->finish; - } - - public function getDuration(): float - { - return $this->duration; - } - - public function getProcessing(): float - { - return $this->processing; - } - - public function getOperating(): float - { - return $this->operating; - } - - public function getOperatingResetAt(): ?int - { - return $this->operatingResetAt; - } - - public function getDateStart(): DateTimeImmutable - { - return $this->dateStart; - } - - public function getDateFinish(): DateTimeImmutable - { - return $this->dateFinish; - } - /** * @throws Exception */ @@ -79,8 +39,8 @@ public static function initFromResponse(array $response): self (float)$response['duration'], (float)$response['processing'], array_key_exists('operating', $response) ? (float)$response['operating'] : 0, - new DateTimeImmutable($response['date_start']), - new DateTimeImmutable($response['date_finish']), + new CarbonImmutable($response['date_start']), + new CarbonImmutable($response['date_finish']), $response['operating_reset_at'] ?? null ); } diff --git a/src/Services/CRM/Common/Result/AbstractCrmItem.php b/src/Services/CRM/Common/Result/AbstractCrmItem.php index dafb3540..34f3da26 100644 --- a/src/Services/CRM/Common/Result/AbstractCrmItem.php +++ b/src/Services/CRM/Common/Result/AbstractCrmItem.php @@ -12,7 +12,7 @@ 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 DateTimeImmutable; +use Carbon\CarbonImmutable; use Money\Currency; use Money\Money; @@ -36,7 +36,7 @@ public function __construct(array $data, Currency $currency = null) /** * @param int|string $offset * - * @return bool|DateTimeImmutable|int|mixed|null + * @return bool|CarbonImmutable|int|mixed|null */ public function __get($offset) @@ -116,7 +116,7 @@ public function __get($offset) case 'movedTime': case 'lastActivityTime': if ($this->data[$offset] !== '') { - return DateTimeImmutable::createFromFormat(DATE_ATOM, $this->data[$offset]); + return CarbonImmutable::createFromFormat(DATE_ATOM, $this->data[$offset]); } return null; diff --git a/src/Services/CRM/Deal/Result/DealCategoryItemResult.php b/src/Services/CRM/Deal/Result/DealCategoryItemResult.php index 46d4c239..fff65ecf 100644 --- a/src/Services/CRM/Deal/Result/DealCategoryItemResult.php +++ b/src/Services/CRM/Deal/Result/DealCategoryItemResult.php @@ -5,13 +5,13 @@ namespace Bitrix24\SDK\Services\CRM\Deal\Result; use Bitrix24\SDK\Services\CRM\Common\Result\AbstractCrmItem; -use DateTimeImmutable; +use Carbon\CarbonImmutable; /** * Class DealItemResult * * @property int $ID - * @property DateTimeImmutable $CREATED_DATE + * @property CarbonImmutable $CREATED_DATE * @property string $NAME * @property bool $IS_LOCKED * @property int $SORT diff --git a/src/Services/CRM/Item/Result/ItemItemResult.php b/src/Services/CRM/Item/Result/ItemItemResult.php index 3d7090a8..e67f5b10 100644 --- a/src/Services/CRM/Item/Result/ItemItemResult.php +++ b/src/Services/CRM/Item/Result/ItemItemResult.php @@ -5,7 +5,7 @@ namespace Bitrix24\SDK\Services\CRM\Item\Result; use Bitrix24\SDK\Services\CRM\Common\Result\AbstractCrmItem; -use DateTimeImmutable; +use Carbon\CarbonImmutable; use Money\Currency; /** @@ -15,14 +15,14 @@ * @property-read int $createdBy * @property-read int $updatedBy * @property-read int $movedBy - * @property-read DateTimeImmutable $createdTime - * @property-read DateTimeImmutable $updatedTime - * @property-read DateTimeImmutable $movedTime + * @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 DateTimeImmutable $begindate - * @property-read DateTimeImmutable $closedate + * @property-read CarbonImmutable $begindate + * @property-read CarbonImmutable $closedate * @property-read int $companyId * @property-read int $contactId * @property-read int $opportunity @@ -38,7 +38,7 @@ * @property-read int $webformId * @property-read int $assignedById * @property-read int $lastActivityBy - * @property-read DateTimeImmutable $lastActivityTime + * @property-read CarbonImmutable $lastActivityTime * @property-read string $utmSource * @property-read string $utmMedium * @property-read string $utmCampaign diff --git a/src/Services/Catalog/Common/Result/AbstractCatalogItem.php b/src/Services/Catalog/Common/Result/AbstractCatalogItem.php index b1d0138a..6f4bed8d 100644 --- a/src/Services/Catalog/Common/Result/AbstractCatalogItem.php +++ b/src/Services/Catalog/Common/Result/AbstractCatalogItem.php @@ -7,9 +7,8 @@ use Bitrix24\SDK\Core\Result\AbstractItem; use Bitrix24\SDK\Services\Catalog\Common\ProductType; use Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNotFoundException; -use DateTimeImmutable; +use Carbon\CarbonImmutable; use Money\Currency; -use Money\Money; abstract class AbstractCatalogItem extends AbstractItem { @@ -31,7 +30,7 @@ public function __construct(array $data, Currency $currency = null) /** * @param int|string $offset * - * @return bool|DateTimeImmutable|int|mixed|null + * @return bool|CarbonImmutable|int|mixed|null */ public function __get($offset) @@ -72,7 +71,7 @@ public function __get($offset) case 'dateCreate': case 'timestampX': if ($this->data[$offset] !== '') { - return DateTimeImmutable::createFromFormat(DATE_ATOM, $this->data[$offset]); + return CarbonImmutable::createFromFormat(DATE_ATOM, $this->data[$offset]); } return null; diff --git a/src/Services/Main/Result/ServerTimeResult.php b/src/Services/Main/Result/ServerTimeResult.php index 45d11321..8a3c1e81 100644 --- a/src/Services/Main/Result/ServerTimeResult.php +++ b/src/Services/Main/Result/ServerTimeResult.php @@ -4,18 +4,20 @@ namespace Bitrix24\SDK\Services\Main\Result; +use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Result\AbstractResult; -use DateTimeImmutable; +use Carbon\CarbonImmutable; +use Exception; class ServerTimeResult extends AbstractResult { /** - * @return \DateTimeImmutable - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Exception + * @return CarbonImmutable + * @throws BaseException + * @throws Exception */ - public function time(): DateTimeImmutable + public function time(): CarbonImmutable { - return new DateTimeImmutable($this->getCoreResponse()->getResponseData()->getResult()[0]); + return new CarbonImmutable($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 index b3588db0..09338ed1 100644 --- a/src/Services/Workflows/Task/Result/WorkflowTaskItemResult.php +++ b/src/Services/Workflows/Task/Result/WorkflowTaskItemResult.php @@ -11,7 +11,6 @@ use Bitrix24\SDK\Services\Workflows\Common\WorkflowTaskStatusType; use Bitrix24\SDK\Services\Workflows\Common\WorkflowTaskUserStatusType; use Carbon\CarbonImmutable; -use DateTimeImmutable; /** * @property-read int $ID task ID diff --git a/src/Services/Workflows/Template/Result/WorkflowTemplateItemResult.php b/src/Services/Workflows/Template/Result/WorkflowTemplateItemResult.php index 13a95c00..a89ea60a 100644 --- a/src/Services/Workflows/Template/Result/WorkflowTemplateItemResult.php +++ b/src/Services/Workflows/Template/Result/WorkflowTemplateItemResult.php @@ -6,7 +6,7 @@ use Bitrix24\SDK\Core\Result\AbstractItem; use Bitrix24\SDK\Services\Workflows\Common\WorkflowAutoExecutionType; -use DateTimeImmutable; +use Carbon\CarbonImmutable; /** * @property-read int $ID @@ -19,7 +19,7 @@ * @property-read ?array $PARAMETERS * @property-read ?array $VARIABLES * @property-read ?array $CONSTANTS - * @property-read ?DateTimeImmutable $MODIFIED + * @property-read ?CarbonImmutable $MODIFIED * @property-read ?bool $IS_MODIFIED * @property-read ?int $USER_ID * @property-read ?string $SYSTEM_CODE @@ -39,7 +39,7 @@ public function __get($offset) return null; case 'MODIFIED': if ($this->data[$offset] !== '') { - return DateTimeImmutable::createFromFormat(DATE_ATOM, $this->data[$offset]); + return CarbonImmutable::createFromFormat(DATE_ATOM, $this->data[$offset]); } return null; case 'IS_MODIFIED': diff --git a/src/Services/Workflows/Workflow/Result/WorkflowInstanceItemResult.php b/src/Services/Workflows/Workflow/Result/WorkflowInstanceItemResult.php index d5df6c77..a8397d8a 100644 --- a/src/Services/Workflows/Workflow/Result/WorkflowInstanceItemResult.php +++ b/src/Services/Workflows/Workflow/Result/WorkflowInstanceItemResult.php @@ -6,14 +6,13 @@ use Bitrix24\SDK\Core\Result\AbstractItem; use Bitrix24\SDK\Services\Workflows\Common\WorkflowAutoExecutionType; -use DateTimeImmutable; -use DateTimeInterface; +use Carbon\CarbonImmutable; /** * @property-read string $ID workflow ID - * @property-read DateTimeImmutable $MODIFIED - * @property-read ?DateTimeImmutable $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 ?DateTimeImmutable $STARTED workflow launch date; + * @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; @@ -37,7 +36,7 @@ public function __get($offset) case 'MODIFIED': case 'STARTED': if ($this->data[$offset] !== '') { - return DateTimeImmutable::createFromFormat(DATE_ATOM, $this->data[$offset]); + return CarbonImmutable::createFromFormat(DATE_ATOM, $this->data[$offset]); } return null; } diff --git a/tests/Unit/Core/Response/DTO/TimeTest.php b/tests/Unit/Core/Response/DTO/TimeTest.php index 34a4585b..fd98be0b 100644 --- a/tests/Unit/Core/Response/DTO/TimeTest.php +++ b/tests/Unit/Core/Response/DTO/TimeTest.php @@ -23,14 +23,14 @@ public function testInitFromResponseData(array $result): void { $time = Time::initFromResponse($result); - $this->assertEquals($result['start'], $time->getStart()); - $this->assertEquals($result['finish'], $time->getFinish()); - $this->assertEquals($result['duration'], $time->getDuration()); - $this->assertEquals($result['processing'], $time->getProcessing()); - $this->assertEquals($result['operating'], $time->getOperating()); - $this->assertEquals($result['operating_reset_at'], $time->getOperatingResetAt()); - $this->assertEquals($result['date_start'], $time->getDateStart()->format(\DATE_ATOM)); - $this->assertEquals($result['date_finish'], $time->getDateFinish()->format(\DATE_ATOM)); + $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 diff --git a/tests/Unit/Stubs/NullBatch.php b/tests/Unit/Stubs/NullBatch.php index fc6b0a7c..d3109e8c 100644 --- a/tests/Unit/Stubs/NullBatch.php +++ b/tests/Unit/Stubs/NullBatch.php @@ -9,7 +9,7 @@ use Bitrix24\SDK\Core\Response\DTO\Pagination; use Bitrix24\SDK\Core\Response\DTO\ResponseData; use Bitrix24\SDK\Core\Response\DTO\Time; -use DateTimeImmutable; +use Carbon\CarbonImmutable; use Generator; class NullBatch implements BatchOperationsInterface @@ -41,7 +41,7 @@ public function getTraversableListWithCount( */ public function addEntityItems(string $apiMethod, array $entityItems): Generator { - yield new ResponseData([],new Time(0,0,0,0,0, new DateTimeImmutable(),new DateTimeImmutable(),0,),new Pagination()); + yield new ResponseData([],new Time(0,0,0,0,0, new CarbonImmutable(),new CarbonImmutable(),0,),new Pagination()); } /** @@ -49,7 +49,7 @@ public function addEntityItems(string $apiMethod, array $entityItems): Generator */ public function deleteEntityItems(string $apiMethod, array $entityItemId): Generator { - yield new ResponseData([],new Time(0,0,0,0,0, new DateTimeImmutable(),new DateTimeImmutable(),0,),new Pagination()); + yield new ResponseData([],new Time(0,0,0,0,0, new CarbonImmutable(),new CarbonImmutable(),0,),new Pagination()); } /** @@ -57,6 +57,6 @@ public function deleteEntityItems(string $apiMethod, array $entityItemId): Gener */ public function updateEntityItems(string $apiMethod, array $entityItems): Generator { - yield new ResponseData([],new Time(0,0,0,0,0, new DateTimeImmutable(),new DateTimeImmutable(),0,),new Pagination()); + 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/tools/Commands/PerformanceBenchmarks/ListCommand.php b/tools/Commands/PerformanceBenchmarks/ListCommand.php index 88ed9fc0..31b8e1d4 100644 --- a/tools/Commands/PerformanceBenchmarks/ListCommand.php +++ b/tools/Commands/PerformanceBenchmarks/ListCommand.php @@ -426,10 +426,10 @@ protected function simpleList(array $order, array $filter, array $select): array ); return [ - 'order_count' => $default->getResponseData()->getTime()->getDuration(), - 'order_without_count' => $orderAndNoCount->getResponseData()->getTime()->getDuration(), - 'without_order_count' => $noOrderAndCount->getResponseData()->getTime()->getDuration(), - 'without_order_without_count' => $noOrderAndNoCount->getResponseData()->getTime()->getDuration(), + '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 From e6b817b0abaadad7a607143c1d53d2b5e0cf70d8 Mon Sep 17 00:00:00 2001 From: mesilov Date: Tue, 13 Aug 2024 01:41:36 +0600 Subject: [PATCH 125/138] Add discount fields and types to CRM models Updated CRM models to include new discount-related fields and types. Improved type annotation consistency by switching to CarbonImmutable for date fields. Enhanced integration tests to cover new discount properties and validation. Signed-off-by: mesilov --- CHANGELOG.md | 4 +- composer.json | 2 + phpunit.xml.dist | 3 +- .../Activity/Result/ActivityItemResult.php | 2 +- .../CRM/Common/Result/AbstractCrmItem.php | 32 +++-- .../CRM/Common/Result/DiscountType.php | 11 ++ .../CRM/Contact/Result/ContactItemResult.php | 96 +++++++------- .../CRM/Deal/Result/DealItemResult.php | 9 +- .../Deal/Result/DealProductRowItemResult.php | 37 +++--- .../CRM/Lead/Result/LeadItemResult.php | 4 +- .../Product/Result/ProductItemResult.php | 10 +- .../Result/WorkflowTemplatesResult.php | 3 - tests/Builders/DemoDataGenerator.php | 16 +++ .../CRM/Deal/Service/DealProductRowsTest.php | 124 +++++++++++------- 14 files changed, 211 insertions(+), 142 deletions(-) create mode 100644 src/Services/CRM/Common/Result/DiscountType.php diff --git a/CHANGELOG.md b/CHANGELOG.md index b4130092..03eb5889 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,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 @@ -57,6 +58,7 @@ * 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` * improve DX - add [Rector](https://github.com/rectorphp/rector) for improve code quality and speed up releases cycle ### Changed @@ -121,7 +123,7 @@ * add `SipRegistrationStatus` – pbx sip line registration status * 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` ### Deleted * remove class `Bitrix24\SDK\Application\Requests\Events\OnApplicationInstall\Auth` diff --git a/composer.json b/composer.json index 5ec8df5b..319e7751 100644 --- a/composer.json +++ b/composer.json @@ -33,6 +33,7 @@ "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", @@ -44,6 +45,7 @@ "symfony/uid": "^6 || ^7" }, "require-dev": { + "typhoon/reflection": "^0.4", "fakerphp/faker": "^1", "monolog/monolog": "^3", "nunomaduro/phpinsights": "^2", diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 171b2a98..ceb84608 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,7 +1,8 @@ + bootstrap="tests/bootstrap.php" failOnRisky="true" failOnWarning="true" + displayDetailsOnTestsThatTriggerWarnings="true"> diff --git a/src/Services/CRM/Activity/Result/ActivityItemResult.php b/src/Services/CRM/Activity/Result/ActivityItemResult.php index 72062fd8..f1755bce 100644 --- a/src/Services/CRM/Activity/Result/ActivityItemResult.php +++ b/src/Services/CRM/Activity/Result/ActivityItemResult.php @@ -5,7 +5,7 @@ namespace Bitrix24\SDK\Services\CRM\Activity\Result; use Bitrix24\SDK\Services\CRM\Common\Result\AbstractCrmItem; -use DateTimeInterface; +use Carbon\CarbonImmutable; /** * @see https://training.bitrix24.com/rest_help/crm/rest_activity/crm_activity_fields.php diff --git a/src/Services/CRM/Common/Result/AbstractCrmItem.php b/src/Services/CRM/Common/Result/AbstractCrmItem.php index 34f3da26..512d21f6 100644 --- a/src/Services/CRM/Common/Result/AbstractCrmItem.php +++ b/src/Services/CRM/Common/Result/AbstractCrmItem.php @@ -15,30 +15,18 @@ use Carbon\CarbonImmutable; use Money\Currency; use Money\Money; +use MoneyPHP\Percentage\Percentage; class AbstractCrmItem extends AbstractItem { - private const CRM_USERFIELD_PREFIX = 'UF_CRM_'; - - /** - * @var Currency - */ private Currency $currency; - - public function __construct(array $data, Currency $currency = null) - { - parent::__construct($data); - if ($currency !== null) { - $this->currency = $currency; - } - } + private const CRM_USERFIELD_PREFIX = 'UF_CRM_'; /** * @param int|string $offset * * @return bool|CarbonImmutable|int|mixed|null */ - public function __get($offset) { // todo унести в отдельный класс и покрыть тестами @@ -104,6 +92,8 @@ public function __get($offset) case 'IS_RECURRING': case 'IS_RETURN_CUSTOMER': case 'IS_REPEATED_APPROACH': + case 'TAX_INCLUDED': + case 'CUSTOMIZED': return $this->data[$offset] === 'Y'; case 'DATE_CREATE': case 'CREATED_DATE': @@ -125,6 +115,7 @@ public function __get($offset) case 'PRICE_NETTO': case 'PRICE_BRUTTO': case 'PRICE': + case 'DISCOUNT_SUM': if ($this->data[$offset] !== '' && $this->data[$offset] !== null) { $var = $this->data[$offset] * 100; return new Money((string)$var, new Currency($this->currency->getCode())); @@ -172,12 +163,17 @@ public function __get($offset) 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]); default: return $this->data[$offset] ?? null; } @@ -202,4 +198,12 @@ protected function getKeyWithUserfieldByFieldName(string $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..fb380026 --- /dev/null +++ b/src/Services/CRM/Common/Result/DiscountType.php @@ -0,0 +1,11 @@ +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/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php index 2c286da0..36b64180 100644 --- a/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php +++ b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php @@ -4,26 +4,58 @@ 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 Money\Currencies\ISOCurrencies; -use Money\Currency; -use Money\Formatter\DecimalMoneyFormatter; -use Money\Money; +use MoneyPHP\Percentage\Percentage; use PHPUnit\Framework\TestCase; +use Typhoon\Reflection\TyphoonReflector; -/** - * Class DealsTest - * - * @package Bitrix24\SDK\Tests\Integration\Services\CRM\Deals\Service - */ class DealProductRowsTest extends TestCase { - protected Deal $dealService; - protected DealProductRows $dealProductRowsService; + 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 @@ -32,67 +64,65 @@ class DealProductRowsTest extends TestCase */ public function testSet(): void { - - $callCosts = new Money(1050, new Currency('USD')); - $currencies = new ISOCurrencies(); - - $moneyFormatter = new DecimalMoneyFormatter($currencies); - $newDealId = $this->dealService->add(['TITLE' => 'test deal'])->getId(); - $this::assertCount(5, $this->dealProductRowsService->get($newDealId)->getProductRows()); + $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( - $newDealId, + $dealId, [ [ - 'PRODUCT_NAME' => 'wine', - 'PRICE' => $moneyFormatter->format($callCosts), + 'PRODUCT_NAME' => sprintf('product name %s', time()), + 'PRICE' => $this->decimalMoneyFormatter->format($price), + 'DISCOUNT_TYPE_ID' => 1, + 'DISCOUNT_SUM' => $this->decimalMoneyFormatter->format($discount) ], ] )->isSuccess() ); - $this::assertCount(1, $this->dealProductRowsService->get($newDealId)->getProductRows()); - - + $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); } - /** - * @throws BaseException - * @throws TransportException - */ public function testGet(): void { - $callCosts = new Money(1050, new Currency('USD')); - $currencies = new ISOCurrencies(); - - $moneyFormatter = new DecimalMoneyFormatter($currencies); - $newDealId = $this->dealService->add(['TITLE' => 'test deal', 'CURRENCY_ID' => $callCosts->getCurrency()->getCode()])->getId(); + $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( - $newDealId, + $dealId, [ [ - 'PRODUCT_NAME' => 'wine', - 'PRICE' => $moneyFormatter->format($callCosts), + 'PRODUCT_NAME' => sprintf('product name %s', time()), + 'PRICE' => $this->decimalMoneyFormatter->format($price), ], ] )->isSuccess() ); - $currency = $callCosts->getCurrency(); - - $resultWithoutAvailableCurrency = $this->dealProductRowsService->get($newDealId); - $resultWithAvailableCurrency = $this->dealProductRowsService->get($newDealId, $currency); - foreach ($resultWithoutAvailableCurrency->getProductRows() as $productRow) { - $this::assertEquals($callCosts, $productRow->PRICE); - } - foreach ($resultWithAvailableCurrency->getProductRows() as $productRow) { - $this::assertEquals($callCosts, $productRow->PRICE); - } + $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->core = Fabric::getCore(); + $this->decimalMoneyFormatter = new DecimalMoneyFormatter(new ISOCurrencies()); + $this->typhoonReflector = TyphoonReflector::build(); } } \ No newline at end of file From 7dae75d7fce2814608839bf7acabf715313ec604 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 17 Aug 2024 21:51:44 +0600 Subject: [PATCH 126/138] Add enums and data filtering in CRM services This commit introduces new enums for CRM Activity types and directions. Also, it adds a data filter class to handle field exclusion by prefix, and updates integration tests to use these new enums. These changes improve the code maintainability and readability in the CRM module. Signed-off-by: mesilov --- src/Core/Fields/FieldsFilter.php | 20 +++ .../CRM/Activity/ActivityContentType.php | 16 +++ .../CRM/Activity/ActivityDirectionType.php | 15 +++ .../CRM/Activity/ActivityNotifyType.php | 16 +++ .../CRM/Activity/ActivityPriority.php | 16 +++ src/Services/CRM/Activity/ActivityStatus.php | 16 +++ src/Services/CRM/Activity/ActivityType.php | 19 +++ .../Activity/Result/ActivityItemResult.php | 74 +++++----- .../CRM/Common/Result/AbstractCrmItem.php | 55 ++++++-- .../CRM/Contact/Result/ContactItemResult.php | 87 ++++++------ .../CRM/Deal/Result/DealItemResult.php | 3 +- tests/Builders/DemoDataGenerator.php | 1 + .../Services/CRM/PhoneNumberBuilder.php | 2 +- tests/Integration/Core/BatchTest.php | 7 +- .../FilterWithBatchWithoutCountOrderTest.php | 3 +- ...ilterWithoutBatchWithoutCountOrderTest.php | 11 +- .../CRM/Activity/Service/ActivityTest.php | 127 +++++++++--------- .../CRM/Activity/Service/BatchTest.php | 7 +- 18 files changed, 331 insertions(+), 164 deletions(-) create mode 100644 src/Core/Fields/FieldsFilter.php create mode 100644 src/Services/CRM/Activity/ActivityContentType.php create mode 100644 src/Services/CRM/Activity/ActivityDirectionType.php create mode 100644 src/Services/CRM/Activity/ActivityNotifyType.php create mode 100644 src/Services/CRM/Activity/ActivityPriority.php create mode 100644 src/Services/CRM/Activity/ActivityStatus.php create mode 100644 src/Services/CRM/Activity/ActivityType.php diff --git a/src/Core/Fields/FieldsFilter.php b/src/Core/Fields/FieldsFilter.php new file mode 100644 index 00000000..a0a4e166 --- /dev/null +++ b/src/Core/Fields/FieldsFilter.php @@ -0,0 +1,20 @@ +data[$offset] !== '' && $this->data[$offset] !== null) { return (int)$this->data[$offset]; } @@ -77,7 +85,6 @@ public function __get($offset) return (int)$this->data[$offset]; } return null; - // contact case 'EXPORT': case 'HAS_PHONE': case 'HAS_EMAIL': @@ -94,9 +101,13 @@ public function __get($offset) 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': @@ -105,22 +116,28 @@ public function __get($offset) case 'updatedTime': case 'movedTime': case 'lastActivityTime': + case 'LAST_ACTIVITY_TIME': if ($this->data[$offset] !== '') { return CarbonImmutable::createFromFormat(DATE_ATOM, $this->data[$offset]); } return null; - // deal 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 []; @@ -174,6 +191,18 @@ public function __get($offset) 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; } @@ -187,7 +216,7 @@ public function __get($offset) * @return mixed|null * @throws UserfieldNotFoundException */ - protected function getKeyWithUserfieldByFieldName(string $fieldName) + protected function getKeyWithUserfieldByFieldName(string $fieldName): mixed { if (!str_starts_with($fieldName, self::CRM_USERFIELD_PREFIX)) { $fieldName = self::CRM_USERFIELD_PREFIX . $fieldName; diff --git a/src/Services/CRM/Contact/Result/ContactItemResult.php b/src/Services/CRM/Contact/Result/ContactItemResult.php index c647a814..21744187 100644 --- a/src/Services/CRM/Contact/Result/ContactItemResult.php +++ b/src/Services/CRM/Contact/Result/ContactItemResult.php @@ -13,55 +13,56 @@ use Carbon\CarbonImmutable; /** - * Class ContactItemResult - * - * @property-read int $ID - * @property-read string $HONORIFIC - * @property-read string $NAME - * @property-read string $SECOND_NAME - * @property-read string $LAST_NAME - * @property-read string $PHOTO - * @property-read null|CarbonImmutable $BIRTHDATE - * @property-read string $TYPE_ID - * @property-read string $SOURCE_ID - * @property-read string $SOURCE_DESCRIPTION - * @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 $COMMENTS - * @property-read string $OPENED - * @property-read bool $EXPORT - * @property-read string $HAS_PHONE - * @property-read string $HAS_EMAIL - * @property-read string $HAS_IMOL + * @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 int $MODIFY_BY_ID * @property-read CarbonImmutable $DATE_CREATE * @property-read CarbonImmutable $DATE_MODIFY - * @property-read string $COMPANY_ID - * @property-read string $COMPANY_IDS - * @property-read int $LEAD_ID - * @property-read string $ORIGINATOR_ID - * @property-read string $ORIGIN_ID - * @property-read string $ORIGIN_VERSION - * @property-read int $FACE_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 int|null $FACE_ID + * @property-read bool $EXPORT * @property-read Email[] $EMAIL - * @property-read Website[] $WEB + * @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 { @@ -71,7 +72,7 @@ class ContactItemResult extends AbstractCrmItem * @return mixed|null * @throws UserfieldNotFoundException */ - public function getUserfieldByFieldName(string $userfieldName) + public function getUserfieldByFieldName(string $userfieldName): mixed { return $this->getKeyWithUserfieldByFieldName($userfieldName); } diff --git a/src/Services/CRM/Deal/Result/DealItemResult.php b/src/Services/CRM/Deal/Result/DealItemResult.php index af4824d6..7deb3854 100644 --- a/src/Services/CRM/Deal/Result/DealItemResult.php +++ b/src/Services/CRM/Deal/Result/DealItemResult.php @@ -10,7 +10,6 @@ /** * Class DealItemResult - * * @property-read int $ID * @property-read string|null $TITLE deal title * @property-read string|null $TYPE_ID @@ -26,7 +25,7 @@ * @property-read string|null $TAX_VALUE * @property-read int|null $LEAD_ID * @property-read int|null $COMPANY_ID - * @property-read int|null $CONTACT_ID + * @property-read int|null $CONTACT_ID deprecated * @property-read int|null $QUOTE_ID * @property-read CarbonImmutable|null $BEGINDATE * @property-read CarbonImmutable|null $CLOSEDATE diff --git a/tests/Builders/DemoDataGenerator.php b/tests/Builders/DemoDataGenerator.php index fb9be9f8..2d7a0360 100644 --- a/tests/Builders/DemoDataGenerator.php +++ b/tests/Builders/DemoDataGenerator.php @@ -1,4 +1,5 @@ length) . substr((string)random_int(1000, PHP_INT_MAX), 0, 3); + 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/Integration/Core/BatchTest.php b/tests/Integration/Core/BatchTest.php index 1aaf427e..98dc2bcb 100644 --- a/tests/Integration/Core/BatchTest.php +++ b/tests/Integration/Core/BatchTest.php @@ -7,6 +7,7 @@ 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; @@ -46,7 +47,7 @@ public function testGetTraversableListWithMoreThanMaxBatchPageCountWithoutLimit( 'TITLE' => sprintf('deal-%s', $i), 'IS_MANUAL_OPPORTUNITY' => 'Y', 'OPPORTUNITY' => sprintf('%s.00', random_int(100, 40000)), - 'CURRENCY_ID' => 'RUB', + 'CURRENCY_ID' => DemoDataGenerator::getCurrency()->getCode(), 'CONTACT_ID' => $contactId, ]; } @@ -136,7 +137,7 @@ public function testGetTraversableListWithLessThanPageSizeWithLimit(): void 'TITLE' => sprintf('deal-%s', $i), 'IS_MANUAL_OPPORTUNITY' => 'Y', 'OPPORTUNITY' => sprintf('%s.00', random_int(100, 40000)), - 'CURRENCY_ID' => 'RUB', + 'CURRENCY_ID' => DemoDataGenerator::getCurrency()->getCode(), 'CONTACT_ID' => $contactId, ]; } @@ -213,7 +214,7 @@ public function testGetTraversableListWithLessThanPageSizeWithoutLimit(): void 'TITLE' => sprintf('deal-%s', $i), 'IS_MANUAL_OPPORTUNITY' => 'Y', 'OPPORTUNITY' => sprintf('%s.00', random_int(100, 40000)), - 'CURRENCY_ID' => 'RUB', + 'CURRENCY_ID' => DemoDataGenerator::getCurrency()->getCode(), 'CONTACT_ID' => $contactId, ]; } diff --git a/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrderTest.php b/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrderTest.php index 3c37725d..c644c8a1 100644 --- a/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrderTest.php +++ b/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrderTest.php @@ -7,6 +7,7 @@ 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; @@ -96,7 +97,7 @@ public function setUp(): void 'TITLE' => sprintf('deal-%s', $i), 'IS_MANUAL_OPPORTUNITY' => 'Y', 'OPPORTUNITY' => sprintf('%s.00', random_int(100, 40000)), - 'CURRENCY_ID' => 'RUB', + 'CURRENCY_ID' => DemoDataGenerator::getCurrency()->getCode(), 'CONTACT_ID' => $this->contactId, ]; } diff --git a/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrderTest.php b/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrderTest.php index 9d6b7002..055313b3 100644 --- a/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrderTest.php +++ b/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrderTest.php @@ -8,6 +8,7 @@ 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; @@ -93,7 +94,7 @@ public function setUp(): void // add contact $this->contactId = $this->serviceBuilder->getCRMScope()->contact()->add( [ - 'NAME' => sprintf('first_%s', time()), + 'NAME' => sprintf('first_%s', time()), 'SECOND' => sprintf('second_%s', time()), ] )->getId(); @@ -105,11 +106,11 @@ public function setUp(): void // 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), + 'TITLE' => sprintf('deal-%s', $i), 'IS_MANUAL_OPPORTUNITY' => 'Y', - 'OPPORTUNITY' => sprintf('%s.00', random_int(100, 40000)), - 'CURRENCY_ID' => 'RUB', - 'CONTACT_ID' => $this->contactId, + '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) { diff --git a/tests/Integration/Services/CRM/Activity/Service/ActivityTest.php b/tests/Integration/Services/CRM/Activity/Service/ActivityTest.php index f0b0acfc..7bcfa784 100644 --- a/tests/Integration/Services/CRM/Activity/Service/ActivityTest.php +++ b/tests/Integration/Services/CRM/Activity/Service/ActivityTest.php @@ -6,10 +6,17 @@ 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 { @@ -29,19 +36,19 @@ public function testAdd(): void $this->contactId[] = $contactId; $this->activityId[] = $this->activityService->add( [ - 'OWNER_ID' => $contactId, - 'OWNER_TYPE_ID' => 3, - 'TYPE_ID' => 2, - 'PROVIDER_ID' => 'VOXIMPLANT_CALL', + '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', + 'SUBJECT' => 'test activity', + 'DESCRIPTION' => 'test activity description', 'DESCRIPTION_TYPE' => '1', - 'DIRECTION' => '2', - 'COMMUNICATIONS' => [ + 'DIRECTION' => '2', + 'COMMUNICATIONS' => [ 0 => [ - 'TYPE' => 'PHONE', - 'VALUE' => '+79780194444', + 'TYPE' => 'PHONE', + 'VALUE' => DemoDataGenerator::getMobilePhone()->getNationalNumber(), ], ], ] @@ -61,19 +68,19 @@ public function testDelete(): void $this->contactId[] = $contactId; $activityId = $this->activityService->add( [ - 'OWNER_ID' => $contactId, - 'OWNER_TYPE_ID' => 3, - 'TYPE_ID' => 2, - 'PROVIDER_ID' => 'VOXIMPLANT_CALL', + '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', + 'SUBJECT' => 'test activity', + 'DESCRIPTION' => 'test activity description', 'DESCRIPTION_TYPE' => '1', - 'DIRECTION' => '2', - 'COMMUNICATIONS' => [ + 'DIRECTION' => '2', + 'COMMUNICATIONS' => [ 0 => [ - 'TYPE' => 'PHONE', - 'VALUE' => '+79780194444', + 'TYPE' => 'PHONE', + 'VALUE' => DemoDataGenerator::getMobilePhone()->getNationalNumber(), ], ], ] @@ -102,19 +109,19 @@ public function testGet(): void $this->contactId[] = $contactId; $newActivity = [ - 'OWNER_ID' => $contactId, - 'OWNER_TYPE_ID' => 3, - 'TYPE_ID' => 2, - 'PROVIDER_ID' => 'VOXIMPLANT_CALL', + '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', + 'SUBJECT' => 'test activity', + 'DESCRIPTION' => 'test activity description', 'DESCRIPTION_TYPE' => '1', - 'DIRECTION' => '2', - 'COMMUNICATIONS' => [ + 'DIRECTION' => '2', + 'COMMUNICATIONS' => [ 0 => [ - 'TYPE' => 'PHONE', - 'VALUE' => '+79780194444', + 'TYPE' => 'PHONE', + 'VALUE' => DemoDataGenerator::getMobilePhone()->getNationalNumber(), ], ], ]; @@ -140,19 +147,19 @@ public function testList(): void $newActivity = []; for ($i = 1; $i < 10; $i++) { $newActivity[$i] = [ - 'OWNER_ID' => $contactId, - 'OWNER_TYPE_ID' => 3, - 'TYPE_ID' => 2, - 'PROVIDER_ID' => 'VOXIMPLANT_CALL', + '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', + 'SUBJECT' => sprintf('test activity - %s', $i), + 'DESCRIPTION' => 'test activity description', 'DESCRIPTION_TYPE' => '1', - 'DIRECTION' => '2', - 'COMMUNICATIONS' => [ + 'DIRECTION' => '2', + 'COMMUNICATIONS' => [ 0 => [ - 'TYPE' => 'PHONE', - 'VALUE' => '+79780194444', + 'TYPE' => 'PHONE', + 'VALUE' => DemoDataGenerator::getMobilePhone()->getNationalNumber(), ], ], ]; @@ -181,19 +188,19 @@ public function testUpdate(): void $this->contactId[] = $contactId; $newActivity = [ - 'OWNER_ID' => $contactId, - 'OWNER_TYPE_ID' => 3, - 'TYPE_ID' => 2, - 'PROVIDER_ID' => 'VOXIMPLANT_CALL', + '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', + 'SUBJECT' => 'test activity', + 'DESCRIPTION' => 'test activity description', 'DESCRIPTION_TYPE' => '1', - 'DIRECTION' => '2', - 'COMMUNICATIONS' => [ + 'DIRECTION' => '2', + 'COMMUNICATIONS' => [ 0 => [ - 'TYPE' => 'PHONE', - 'VALUE' => '+79780194444', + 'TYPE' => 'PHONE', + 'VALUE' => DemoDataGenerator::getMobilePhone()->getNationalNumber(), ], ], ]; @@ -220,19 +227,19 @@ public function testCountByFilter(): void $newActivity = []; for ($i = 1; $i < 10; $i++) { $newActivity[$i] = [ - 'OWNER_ID' => $contactId, - 'OWNER_TYPE_ID' => 3, - 'TYPE_ID' => 2, - 'PROVIDER_ID' => 'VOXIMPLANT_CALL', + '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', + 'SUBJECT' => sprintf('test activity - %s', $i), + 'DESCRIPTION' => 'test activity description', 'DESCRIPTION_TYPE' => '1', - 'DIRECTION' => '2', - 'COMMUNICATIONS' => [ + 'DIRECTION' => '2', + 'COMMUNICATIONS' => [ 0 => [ - 'TYPE' => 'PHONE', - 'VALUE' => '+79780194444', + 'TYPE' => 'PHONE', + 'VALUE' => DemoDataGenerator::getMobilePhone()->getNationalNumber(), ], ], ]; diff --git a/tests/Integration/Services/CRM/Activity/Service/BatchTest.php b/tests/Integration/Services/CRM/Activity/Service/BatchTest.php index f848cb7e..c7e8aadd 100644 --- a/tests/Integration/Services/CRM/Activity/Service/BatchTest.php +++ b/tests/Integration/Services/CRM/Activity/Service/BatchTest.php @@ -8,6 +8,7 @@ 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; @@ -43,7 +44,7 @@ public function testBatchAdd(): void 'COMMUNICATIONS' => [ 0 => [ 'TYPE' => 'PHONE', - 'VALUE' => '+79780194444', + 'VALUE' => DemoDataGenerator::getMobilePhone()->getNationalNumber(), ], ], ]; @@ -89,7 +90,7 @@ public function testBatchDelete(): void 'COMMUNICATIONS' => [ 0 => [ 'TYPE' => 'PHONE', - 'VALUE' => '+79780194444', + 'VALUE' => DemoDataGenerator::getMobilePhone()->getNationalNumber(), ], ], ]; @@ -146,7 +147,7 @@ public function testBatchList(): void 'COMMUNICATIONS' => [ 0 => [ 'TYPE' => 'PHONE', - 'VALUE' => '+79780194444', + 'VALUE' => DemoDataGenerator::getMobilePhone()->getNationalNumber(), ], ], ]; From 9adf3a74287d11ee5e40845b3e38ec930923c2a4 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sat, 17 Aug 2024 21:53:26 +0600 Subject: [PATCH 127/138] Add custom Bitrix24 assertion and integration test. Introduced a new trait `CustomBitrix24Assertions` for verifying Bitrix24 API fields against PHPDoc annotations. Incorporated the new assertion in `ContactTest` and adjusted `composer.json` to include necessary dependencies. Signed-off-by: mesilov --- composer.json | 5 +-- .../CustomBitrix24Assertions.php | 36 +++++++++++++++++++ .../CRM/Contact/Service/ContactTest.php | 16 +++++++-- 3 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 tests/CustomAssertions/CustomBitrix24Assertions.php diff --git a/composer.json b/composer.json index 319e7751..36f3e0d1 100644 --- a/composer.json +++ b/composer.json @@ -39,13 +39,13 @@ "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": { - "typhoon/reflection": "^0.4", "fakerphp/faker": "^1", "monolog/monolog": "^3", "nunomaduro/phpinsights": "^2", @@ -55,7 +55,8 @@ "rector/rector": "^1", "roave/security-advisories": "dev-master", "symfony/debug-bundle": "^6 || ^7", - "symfony/stopwatch": "^6 || ^7" + "symfony/stopwatch": "^6 || ^7", + "typhoon/reflection": "^0.4" }, "autoload": { "psr-4": { diff --git a/tests/CustomAssertions/CustomBitrix24Assertions.php b/tests/CustomAssertions/CustomBitrix24Assertions.php new file mode 100644 index 00000000..09e25ab1 --- /dev/null +++ b/tests/CustomAssertions/CustomBitrix24Assertions.php @@ -0,0 +1,36 @@ + $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/Services/CRM/Contact/Service/ContactTest.php b/tests/Integration/Services/CRM/Contact/Service/ContactTest.php index 058555a1..257f63f8 100644 --- a/tests/Integration/Services/CRM/Contact/Service/ContactTest.php +++ b/tests/Integration/Services/CRM/Contact/Service/ContactTest.php @@ -10,7 +10,9 @@ 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; @@ -23,8 +25,10 @@ */ class ContactTest extends TestCase { - protected Contact $contactService; - protected Faker\Generator $faker; + use CustomBitrix24Assertions; + + private Contact $contactService; + private Faker\Generator $faker; /** * @throws BaseException @@ -56,6 +60,12 @@ 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 @@ -203,7 +213,7 @@ public function testGetWebsite(): void 'WEB' => [ [ 'VALUE' => $url, - 'VALUE_TYPE' => WebsiteValueType::work, + 'VALUE_TYPE' => WebsiteValueType::work->name, ] ], ])->getId())->contact()->WEB[0]->VALUE); From ca24152dfa2e54c99042041f140868583380b6a0 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 19 Aug 2024 02:09:52 +0600 Subject: [PATCH 128/138] Add API metadata attributes and command for coverage docs Implemented API metadata attributes for service and method documentation. Added GenerateCoverageDocumentationCommand to generate API coverage documentation in Markdown format. This enhances maintainability and provides comprehensive API documentation automatically. Signed-off-by: mesilov --- bin/console | 11 + docs/EN/Services/bitrix24-php-sdk-methods.md | 20 ++ src/Attributes/ApiBatchMethodMetadata.php | 21 ++ src/Attributes/ApiBatchServiceMetadata.php | 22 ++ src/Attributes/ApiEndpointMetadata.php | 21 ++ src/Attributes/ApiServiceMetadata.php | 22 ++ src/Attributes/Services/AttributesParser.php | 139 +++++++++++ .../GenerateCoverageDocumentationCommand.php | 230 ++++++++++++++++++ .../CRM/Activity/ReadModel/EmailFetcher.php | 23 +- .../CRM/Activity/Service/Activity.php | 62 +++-- src/Services/CRM/Activity/Service/Batch.php | 45 ++-- src/Services/CRM/Deal/Service/Deal.php | 35 ++- .../Catalog/Catalog/Service/Catalog.php | 21 +- .../Catalog/Product/Service/Product.php | 29 +++ 14 files changed, 647 insertions(+), 54 deletions(-) create mode 100644 docs/EN/Services/bitrix24-php-sdk-methods.md create mode 100644 src/Attributes/ApiBatchMethodMetadata.php create mode 100644 src/Attributes/ApiBatchServiceMetadata.php create mode 100644 src/Attributes/ApiEndpointMetadata.php create mode 100644 src/Attributes/ApiServiceMetadata.php create mode 100644 src/Attributes/Services/AttributesParser.php create mode 100644 src/Infrastructure/Console/Commands/GenerateCoverageDocumentationCommand.php diff --git a/bin/console b/bin/console index 5a561cd4..8e58fd68 100644 --- a/bin/console +++ b/bin/console @@ -1,8 +1,11 @@ #!/usr/bin/env php 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/docs/EN/Services/bitrix24-php-sdk-methods.md b/docs/EN/Services/bitrix24-php-sdk-methods.md new file mode 100644 index 00000000..418c36b3 --- /dev/null +++ b/docs/EN/Services/bitrix24-php-sdk-methods.md @@ -0,0 +1,20 @@ +## All bitrix24-php-sdk methods + +| **Scope** | **API method with documentation** | **Description** | Method in SDK | +|-----------|----------------------------------------|------------------|----------------| +|`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/feature/390-prepare-publish-2-0/src/Services/Catalog/Catalog/Service/Catalog.php#L34-L37)
Return type
[`Bitrix24\SDK\Services\Catalog\Catalog\Result\CatalogResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Catalog/Service/Catalog.php#L56-L64)
Return type
[`Bitrix24\SDK\Services\Catalog\Catalog\Result\CatalogsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Catalog/Service/Catalog.php#L79-L82)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Product/Service/Product.php#L49-L52)
Return type
[`Bitrix24\SDK\Services\Catalog\Product\Result\ProductResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Product/Service/Product.php#L68-L74)
Return type
[`Bitrix24\SDK\Services\Catalog\Product\Result\ProductResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Product/Service/Product.php#L90-L93)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Product/Service/Product.php#L107-L115)
Return type
[`Bitrix24\SDK\Services\Catalog\Product\Result\ProductsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Product/Service/Product.php#L133-L144)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Core/Result/FieldsResult.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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/Deal.php#L96-L107)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Core/Result/AddedItemResult.php)| +|`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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/Deal.php#L125-L135)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Core/Result/DeletedItemResult.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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L101-L111)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L129-L139)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L155-L158)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L176-L186)
Return type
[`Bitrix24\SDK\Services\CRM\Activity\Result\ActivityResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L297-L310)
Return type
[`Bitrix24\SDK\Services\CRM\Activity\Result\ActivitiesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Result/ActivitiesResult.php)

⚡️Batch methods:
  • `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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L373-L384)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Core/Result/UpdatedItemResult.php)| \ No newline at end of file diff --git a/src/Attributes/ApiBatchMethodMetadata.php b/src/Attributes/ApiBatchMethodMetadata.php new file mode 100644 index 00000000..50776ab9 --- /dev/null +++ b/src/Attributes/ApiBatchMethodMetadata.php @@ -0,0 +1,21 @@ + + */ + 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) { + $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()[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, + '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/Infrastructure/Console/Commands/GenerateCoverageDocumentationCommand.php b/src/Infrastructure/Console/Commands/GenerateCoverageDocumentationCommand.php new file mode 100644 index 00000000..7e7a0a5f --- /dev/null +++ b/src/Infrastructure/Console/Commands/GenerateCoverageDocumentationCommand.php @@ -0,0 +1,230 @@ +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['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»'); + } + + $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/Services/CRM/Activity/ReadModel/EmailFetcher.php b/src/Services/CRM/Activity/ReadModel/EmailFetcher.php index 2b42e249..834ff449 100644 --- a/src/Services/CRM/Activity/ReadModel/EmailFetcher.php +++ b/src/Services/CRM/Activity/ReadModel/EmailFetcher.php @@ -5,16 +5,21 @@ 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 \Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface $bulkItemsReader + * @param BulkItemsReaderInterface $bulkItemsReader */ public function __construct(BulkItemsReaderInterface $bulkItemsReader) { @@ -22,18 +27,18 @@ public function __construct(BulkItemsReaderInterface $bulkItemsReader) } /** - * @param array $order - * @param array $filter - * @param array $select - * @param int|null $limit - * - * @return EmailActivityItemResult[]|Generator - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @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_ID' => 'CRM_EMAIL', 'PROVIDER_TYPE_ID' => 'EMAIL', ]); diff --git a/src/Services/CRM/Activity/Service/Activity.php b/src/Services/CRM/Activity/Service/Activity.php index 9ccde4f7..4124f0ff 100644 --- a/src/Services/CRM/Activity/Service/Activity.php +++ b/src/Services/CRM/Activity/Service/Activity.php @@ -4,7 +4,11 @@ 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; @@ -16,11 +20,7 @@ use Bitrix24\SDK\Services\CRM\Activity\Result\ActivityResult; use Psr\Log\LoggerInterface; -/** - * Class Activity - * - * @package Bitrix24\SDK\Services\CRM\Activity\Service - */ +#[ApiServiceMetadata(new Scope(['crm']))] class Activity extends AbstractService { public Batch $batch; @@ -28,8 +28,8 @@ class Activity extends AbstractService /** * Contact constructor. * - * @param Batch $batch - * @param CoreInterface $core + * @param Batch $batch + * @param CoreInterface $core * @param LoggerInterface $log */ public function __construct(Batch $batch, CoreInterface $core, LoggerInterface $log) @@ -93,6 +93,11 @@ public function __construct(Batch $batch, CoreInterface $core, LoggerInterface $ * @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( @@ -116,6 +121,11 @@ public function add(array $fields): AddedItemResult * @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( @@ -137,6 +147,11 @@ public function delete(int $itemId): DeletedItemResult * @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')); @@ -153,6 +168,11 @@ public function fields(): FieldsResult * @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( @@ -214,7 +234,7 @@ public function get(int $entityId): ActivityResult * COMMUNICATIONS?: string, * FILES?: string, * WEBDAV_ELEMENTS?: string, - * } $order + * } $order * * @param array{ * ID?: int, @@ -260,25 +280,30 @@ public function get(int $entityId): ActivityResult * COMMUNICATIONS?: string, * FILES?: string, * WEBDAV_ELEMENTS?: string, - * } $filter + * } $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 + * @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, + 'order' => $order, 'filter' => $filter, 'select' => $select, - 'start' => $start, + 'start' => $start, ] ) ); @@ -334,19 +359,24 @@ public function list(array $order, array $filter, array $select, int $start): Ac * COMMUNICATIONS?: string, * FILES?: string, * WEBDAV_ELEMENTS?: string, - * } $fields + * } $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, + 'id' => $itemId, 'fields' => $fields, ] ) @@ -403,8 +433,8 @@ public function update(int $itemId, array $fields): UpdatedItemResult * } $filter * * @return int - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws BaseException + * @throws TransportException */ public function countByFilter(array $filter = []): int { diff --git a/src/Services/CRM/Activity/Service/Batch.php b/src/Services/CRM/Activity/Service/Batch.php index d176a977..57bce00a 100644 --- a/src/Services/CRM/Activity/Service/Batch.php +++ b/src/Services/CRM/Activity/Service/Batch.php @@ -4,6 +4,10 @@ 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; @@ -11,11 +15,7 @@ use Bitrix24\SDK\Services\CRM\Activity\Result\ActivityItemResult; use Generator; -/** - * Class Batch - * - * @package Bitrix24\SDK\Services\CRM\Activity\Service - */ +#[ApiBatchServiceMetadata(new Scope(['crm']))] class Batch extends AbstractBatchService { /** @@ -65,7 +65,7 @@ class Batch extends AbstractBatchService * COMMUNICATIONS?: string, * FILES?: string, * WEBDAV_ELEMENTS?: string, - * } $order + * } $order * * @param array{ * ID?: int, @@ -111,22 +111,27 @@ class Batch extends AbstractBatchService * 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'] + * } $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|ActivityItemResult[] + * @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, + 'order' => $order, 'filter' => $filter, 'select' => $select, - 'limit' => $limit, + 'limit' => $limit, ] ); foreach ($this->batch->getTraversableList('crm.activity.list', $order, $filter, $select, $limit) as $key => $value) { @@ -183,9 +188,14 @@ public function list(array $order, array $filter, array $select, ?int $limit = n * WEBDAV_ELEMENTS?: string, * }> $activities * - * @return \Generator - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @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 = []; @@ -204,9 +214,14 @@ public function add(array $activities): Generator * * @param int[] $itemId * - * @return \Generator|\Bitrix24\SDK\Core\Contracts\DeletedItemResultInterface[] - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @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) { diff --git a/src/Services/CRM/Deal/Service/Deal.php b/src/Services/CRM/Deal/Service/Deal.php index 5f37aa57..0e451728 100644 --- a/src/Services/CRM/Deal/Service/Deal.php +++ b/src/Services/CRM/Deal/Service/Deal.php @@ -4,7 +4,9 @@ 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; @@ -15,12 +17,9 @@ 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; -/** - * Class Deals - * - * @package Bitrix24\SDK\Services\CRM\Deals\Client - */ +#[ApiServiceMetadata(new Scope(['crm']))] class Deal extends AbstractService { public Batch $batch; @@ -28,8 +27,8 @@ class Deal extends AbstractService /** * Deal constructor. * - * @param Batch $batch - * @param CoreInterface $core + * @param Batch $batch + * @param CoreInterface $core * @param LoggerInterface $log */ public function __construct(Batch $batch, CoreInterface $core, LoggerInterface $log) @@ -89,6 +88,11 @@ public function __construct(Batch $batch, CoreInterface $core, LoggerInterface $ * @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( @@ -113,6 +117,11 @@ public function add(array $fields, array $params = []): AddedItemResult * @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( @@ -160,9 +169,9 @@ public function get(int $id): DealResult * * @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 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 @@ -175,10 +184,10 @@ public function list(array $order, array $filter, array $select, int $startItem $this->core->call( 'crm.deal.list', [ - 'order' => $order, + 'order' => $order, 'filter' => $filter, 'select' => $select, - 'start' => $startItem, + 'start' => $startItem, ] ) ); @@ -242,7 +251,7 @@ public function update(int $id, array $fields, array $params = []): UpdatedItemR $this->core->call( 'crm.deal.update', [ - 'id' => $id, + 'id' => $id, 'fields' => $fields, 'params' => $params, ] diff --git a/src/Services/Catalog/Catalog/Service/Catalog.php b/src/Services/Catalog/Catalog/Service/Catalog.php index b09c7e61..ece3d4b2 100644 --- a/src/Services/Catalog/Catalog/Service/Catalog.php +++ b/src/Services/Catalog/Catalog/Service/Catalog.php @@ -4,6 +4,9 @@ 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; @@ -11,6 +14,7 @@ use Bitrix24\SDK\Services\Catalog\Catalog\Result\CatalogResult; use Bitrix24\SDK\Services\Catalog\Catalog\Result\CatalogsResult; +#[ApiServiceMetadata(new Scope(['catalog']))] class Catalog extends AbstractService { /** @@ -22,13 +26,18 @@ class Catalog extends AbstractService * @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 by ID. + * The method gets field value of commercial catalog product list * * @see https://training.bitrix24.com/rest_help/catalog/catalog/catalog_catalog_list.php * @param array $select @@ -39,6 +48,11 @@ public function get(int $catalogId): CatalogResult * @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', [ @@ -57,6 +71,11 @@ public function list(array $select, array $filter, array $order, int $start): Ca * @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')); diff --git a/src/Services/Catalog/Product/Service/Product.php b/src/Services/Catalog/Product/Service/Product.php index afb59635..372553d3 100644 --- a/src/Services/Catalog/Product/Service/Product.php +++ b/src/Services/Catalog/Product/Service/Product.php @@ -4,7 +4,10 @@ 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; @@ -16,6 +19,7 @@ use Psr\Log\LoggerInterface; +#[ApiServiceMetadata(new Scope(['catalog']))] class Product extends AbstractService { public Batch $batch; @@ -37,6 +41,11 @@ public function __construct( * @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])); @@ -51,6 +60,11 @@ public function get(int $productId): ProductResult * @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', [ @@ -68,6 +82,11 @@ public function add(array $productFields): ProductResult * @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])); @@ -80,6 +99,11 @@ public function delete(int $productId): DeletedItemResult * @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', [ @@ -101,6 +125,11 @@ public function list(array $select, array $filter, array $order, int $start): Pr * @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 = [ From 86534fe78ebd58c1b47d82be1b1429c6b20822a5 Mon Sep 17 00:00:00 2001 From: mesilov Date: Sun, 25 Aug 2024 02:00:58 +0600 Subject: [PATCH 129/138] Add API metadata annotations and update notification methods Added `ApiServiceMetadata` and `ApiEndpointMetadata` annotations to relevant classes and methods. Updated methods to handle system and personal notifications, including new functionalities for deleting and marking notifications as read or unread. Signed-off-by: mesilov --- CHANGELOG.md | 87 ++++--- Makefile | 24 ++ README.md | 10 +- docs/EN/Development/dev.md | 17 ++ docs/EN/Services/bitrix24-php-sdk-methods.md | 168 +++++++++++++- docs/EN/documentation.md | 16 +- phpstan.neon.dist | 8 +- phpunit.xml.dist | 12 + rector.php | 12 + src/Attributes/Services/AttributesParser.php | 4 +- src/Core/ApiLevelErrorHandler.php | 3 + .../Exceptions/WrongAuthTypeException.php | 8 + src/Core/Fields/FieldsFilter.php | 2 +- .../GenerateCoverageDocumentationCommand.php | 8 +- .../Activity/ReadModel/OpenLineFetcher.php | 24 +- .../Activity/ReadModel/VoximplantFetcher.php | 24 +- .../CRM/Activity/ReadModel/WebFormFetcher.php | 24 +- .../CRM/Activity/Service/Activity.php | 4 +- src/Services/CRM/Contact/Service/Batch.php | 38 +++- src/Services/CRM/Contact/Service/Contact.php | 51 ++++- .../CRM/Contact/Service/ContactUserfield.php | 65 ++++-- src/Services/CRM/Deal/Service/Batch.php | 53 +++-- src/Services/CRM/Deal/Service/Deal.php | 24 +- .../CRM/Deal/Service/DealCategory.php | 62 ++++- .../CRM/Deal/Service/DealCategoryStage.php | 17 +- src/Services/CRM/Deal/Service/DealContact.php | 49 +++- .../CRM/Deal/Service/DealProductRows.php | 26 ++- .../CRM/Deal/Service/DealUserfield.php | 54 ++++- .../CRM/Duplicates/Service/Duplicate.php | 14 ++ src/Services/CRM/Item/Service/Batch.php | 17 +- src/Services/CRM/Item/Service/Item.php | 34 +++ src/Services/CRM/Lead/Service/Batch.php | 32 ++- src/Services/CRM/Lead/Service/Lead.php | 35 ++- src/Services/CRM/Product/Service/Batch.php | 23 +- src/Services/CRM/Product/Service/Product.php | 51 ++++- .../CRM/Settings/Service/Settings.php | 14 +- .../CRM/Userfield/Service/Userfield.php | 19 ++ .../Catalog/Catalog/Service/Catalog.php | 7 - .../Common/Result/AbstractCatalogItem.php | 9 +- .../Catalog/Product/Result/ProductResult.php | 1 + .../Catalog/Product/Service/Product.php | 17 +- src/Services/IM/IMServiceBuilder.php | 14 +- src/Services/IM/Notify/Service/Notify.php | 197 ++++++++++++++++ src/Services/IM/Service/IM.php | 83 ------- .../IMOpenLines/IMOpenLinesServiceBuilder.php | 3 - .../Result/AddedMessageItemResult.php | 1 - .../IMOpenLines/Result/JoinOpenLineResult.php | 1 - src/Services/IMOpenLines/Service/Network.php | 53 ++--- src/Services/Main/MainServiceBuilder.php | 6 - .../Main/Result/EventHandlerBindResult.php | 1 - .../Main/Result/EventHandlerUnbindResult.php | 1 - src/Services/Main/Result/EventListResult.php | 1 - .../Main/Result/IsUserAdminResult.php | 1 - .../Main/Result/MethodAffordabilityResult.php | 2 - src/Services/Main/Result/ServerTimeResult.php | 1 - .../Main/Result/UserProfileItemResult.php | 1 + src/Services/Main/Service/Event.php | 76 ++++--- src/Services/Main/Service/EventManager.php | 30 +-- src/Services/Main/Service/Main.php | 105 ++++++--- .../Placement/PlacementServiceBuilder.php | 6 - .../Placement/Result/DeleteUserTypeResult.php | 1 - .../Placement/Result/PlacementBindResult.php | 1 - .../Result/PlacementLocationCodesResult.php | 1 - .../Result/PlacementUnbindResult.php | 1 - .../Result/RegisterUserTypeResult.php | 1 - src/Services/Placement/Service/Placement.php | 55 +++-- .../Service/PlacementLocationCode.php | 215 +++++++++++++----- .../Placement/Service/UserFieldType.php | 47 ++-- src/Services/Telephony/Call/Service/Call.php | 10 +- .../ExternalCall/Service/ExternalCall.php | 44 ++++ .../ExternalLine/Service/ExternalLine.php | 21 +- .../Voximplant/InfoCall/Service/InfoCall.php | 15 +- .../Voximplant/Line/Service/Line.php | 25 +- .../Telephony/Voximplant/Sip/Service/Sip.php | 35 ++- .../Voximplant/TTS/Voices/Service/Voices.php | 9 + .../Telephony/Voximplant/Url/Service/Url.php | 10 +- .../Voximplant/User/Service/User.php | 31 ++- src/Services/User/Service/User.php | 34 +++ .../Result/UserConsentAgreementResult.php | 4 +- .../Result/UserConsentAgreementTextResult.php | 1 - .../UserConsent/Service/UserConsent.php | 18 +- .../Service/UserConsentAgreement.php | 29 ++- .../UserConsent/UserConsentServiceBuilder.php | 4 - .../Workflows/Activity/Service/Activity.php | 30 ++- .../Workflows/Event/Service/Event.php | 10 +- .../Workflows/Robot/Service/Robot.php | 25 +- src/Services/Workflows/Task/Service/Task.php | 15 +- .../Workflows/Template/Service/Template.php | 25 +- .../Workflows/Workflow/Service/Workflow.php | 25 +- tests/.env | 4 +- .../Catalog/Catalog/Service/CatalogTest.php | 21 +- .../Catalog/Product/Service/ProductTest.php | 62 +++-- .../Services/IM/Service/NotifyTest.php | 160 +++++++++++++ .../IMOpenLines/Service/NetworkTest.php | 31 +-- .../Services/Main/Service/MainTest.php | 64 +++--- .../Placement/Service/PlacementTest.php | 103 +++++++++ .../Service/UserConsentAgreementTest.php | 30 +-- .../UserConsent/Service/UserConsentTest.php | 20 +- .../Unit/Services/IM/IMServiceBuilderTest.php | 10 +- 99 files changed, 2258 insertions(+), 739 deletions(-) create mode 100644 docs/EN/Development/dev.md create mode 100644 src/Core/Exceptions/WrongAuthTypeException.php create mode 100644 src/Services/IM/Notify/Service/Notify.php delete mode 100644 src/Services/IM/Service/IM.php create mode 100644 tests/Integration/Services/IM/Service/NotifyTest.php create mode 100644 tests/Integration/Services/Placement/Service/PlacementTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 03eb5889..0f69316b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,7 +45,7 @@ * 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\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 @@ -55,15 +55,25 @@ * 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 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` -* improve DX - add [Rector](https://github.com/rectorphp/rector) for improve code quality and speed up releases cycle +* 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) +* ❗️ migrate from `DateTimeImmutable` to `CarbonImmutable` from [carbon](https://github.com/briannesbitt/carbon) * ❗️ refactor `Bitrix24\SDK\Application\Contracts`: * ❗️ update scope `telephony`, scope fully rewritten @@ -98,34 +108,52 @@ * `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. + * `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). + * `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 -* change signature `Bitrix24\SDK\Core\Credentials\AccessToken::getRefreshToken()?string;` - add nullable option for event tokens +* ❗️ 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` @@ -135,9 +163,9 @@ ### 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) +* 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 @@ -223,7 +251,8 @@ * 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 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 @@ -297,11 +326,13 @@ , `createFromPlacementRequest` * -❗️deleted [unused class](https://github.com/mesilov/bitrix24-php-sdk/issues/303) `Bitrix24\SDK\Core\Response\DTO\ResponseDataCollection` +❗️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 [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` diff --git a/Makefile b/Makefile index c03dbefd..1e8bffbb 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,21 @@ 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: @@ -9,6 +24,7 @@ lint-rector: lint-rector-fix: vendor/bin/rector process +# unit tests test-unit: vendor/bin/phpunit --testsuite unit_tests --display-warnings @@ -17,7 +33,15 @@ 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 c6dc69ad..9e7120ca 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,10 @@ Performance improvements 🚀 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 ## Sponsors @@ -220,8 +224,4 @@ in this project. ## Need custom Bitrix24 application? -mesilov.maxim@gmail.com for private consultations or dedicated support - -## Documentation - -[Bitrix24 API documentation - English](https://training.bitrix24.com/rest_help/) +Email to mesilov.maxim@gmail.com for private consultations or dedicated support. \ No newline at end of file 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 index 418c36b3..ef1e5489 100644 --- a/docs/EN/Services/bitrix24-php-sdk-methods.md +++ b/docs/EN/Services/bitrix24-php-sdk-methods.md @@ -2,19 +2,163 @@ | **Scope** | **API method with documentation** | **Description** | Method in SDK | |-----------|----------------------------------------|------------------|----------------| -|`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/feature/390-prepare-publish-2-0/src/Services/Catalog/Catalog/Service/Catalog.php#L34-L37)
Return type
[`Bitrix24\SDK\Services\Catalog\Catalog\Result\CatalogResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Catalog/Service/Catalog.php#L56-L64)
Return type
[`Bitrix24\SDK\Services\Catalog\Catalog\Result\CatalogsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Catalog/Service/Catalog.php#L79-L82)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Product/Service/Product.php#L49-L52)
Return type
[`Bitrix24\SDK\Services\Catalog\Product\Result\ProductResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Product/Service/Product.php#L68-L74)
Return type
[`Bitrix24\SDK\Services\Catalog\Product\Result\ProductResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Product/Service/Product.php#L90-L93)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Product/Service/Product.php#L107-L115)
Return type
[`Bitrix24\SDK\Services\Catalog\Product\Result\ProductsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Product/Service/Product.php#L133-L144)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Core/Result/FieldsResult.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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/Deal.php#L96-L107)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Core/Result/AddedItemResult.php)| -|`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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/Deal.php#L125-L135)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Core/Result/DeletedItemResult.php)| +|`–`|[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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L35-L38)
Return type
[`Bitrix24\SDK\Services\Main\Result\ServerTimeResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L52-L55)
Return type
[`Bitrix24\SDK\Services\Main\Result\UserProfileResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L70-L75)
Return type
[`Bitrix24\SDK\Core\Response\Response`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L90-L95)
Return type
[`Bitrix24\SDK\Core\Response\Response`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L110-L117)
Return type
[`Bitrix24\SDK\Services\Main\Result\MethodAffordabilityResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L148-L151)
Return type
[`Bitrix24\SDK\Core\Response\Response`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L203-L206)
Return type
[`Bitrix24\SDK\Core\Response\Response`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L220-L223)
Return type
[`Bitrix24\SDK\Services\Main\Result\ApplicationInfoResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L237-L240)
Return type
[`Bitrix24\SDK\Services\Main\Result\IsUserAdminResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Catalog/Service/Catalog.php#L32-L35)
Return type
[`Bitrix24\SDK\Services\Catalog\Catalog\Result\CatalogResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Catalog/Service/Catalog.php#L49-L57)
Return type
[`Bitrix24\SDK\Services\Catalog\Catalog\Result\CatalogsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Catalog/Service/Catalog.php#L72-L75)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Product/Service/Product.php#L46-L49)
Return type
[`Bitrix24\SDK\Services\Catalog\Product\Result\ProductResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Product/Service/Product.php#L63-L69)
Return type
[`Bitrix24\SDK\Services\Catalog\Product\Result\ProductResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Product/Service/Product.php#L83-L86)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Product/Service/Product.php#L100-L108)
Return type
[`Bitrix24\SDK\Services\Catalog\Product\Result\ProductsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Product/Service/Product.php#L122-L133)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Settings/Service/Settings.php#L28-L31)
Return type
[`Bitrix24\SDK\Services\CRM\Settings\Result\SettingsModeResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Userfield/Service/Userfield.php#L32-L35)
Return type
[`Bitrix24\SDK\Services\CRM\Userfield\Result\UserfieldTypesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Userfield/Service/Userfield.php#L68-L71)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategory.php#L46-L56)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategory.php#L74-L84)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategory.php#L100-L103)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategory.php#L118-L121)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealCategoryResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategory.php#L141-L144)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategory.php#L163-L173)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealCategoryResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategory.php#L225-L235)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealCategoryStatusResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategory.php#L260-L271)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Core/Result/UpdatedItemResult.php)| +|`catalog`|[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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategoryStage.php#L29-L39)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealCategoryStagesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/Deal.php#L96-L107)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/Deal.php#L125-L135)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/Deal.php#L172-L175)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/Deal.php#L196-L209)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/Deal.php#L268-L280)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealProductRows.php#L36-L59)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealProductRowItemsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealProductRows.php#L99-L110)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Core/Result/UpdatedItemResult.php)| +|`catalog`|[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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealUserfield.php#L78-L89)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealUserfieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Result/DealUserfieldsResult.php)| +|`catalog`|[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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealUserfield.php#L130-L150)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Core/Result/AddedItemResult.php)| +|`catalog`|[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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealUserfield.php#L168-L178)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Core/Result/DeletedItemResult.php)| +|`catalog`|[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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealUserfield.php#L195-L205)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealUserfieldResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Result/DealUserfieldResult.php)| +|`catalog`|[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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealUserfield.php#L223-L234)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealContact.php#L40-L55)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealContact.php#L69-L72)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealContact.php#L90-L100)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealContactItemsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealContact.php#L118-L128)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealContact.php#L151-L162)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealContact.php#L181-L194)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/Contact.php#L108-L119)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/Contact.php#L137-L147)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/Contact.php#L163-L166)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/Contact.php#L184-L194)
Return type
[`Bitrix24\SDK\Services\CRM\Contact\Result\ContactResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/Contact.php#L312-L325)
Return type
[`Bitrix24\SDK\Services\CRM\Contact\Result\ContactsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/Contact.php#L392-L404)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/ContactUserfield.php#L76-L87)
Return type
[`Bitrix24\SDK\Services\CRM\Contact\Result\ContactUserfieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/ContactUserfield.php#L128-L148)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/ContactUserfield.php#L166-L176)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/ContactUserfield.php#L193-L203)
Return type
[`Bitrix24\SDK\Services\CRM\Contact\Result\ContactUserfieldResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/ContactUserfield.php#L221-L232)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L101-L111)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L129-L139)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L155-L158)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L176-L186)
Return type
[`Bitrix24\SDK\Services\CRM\Activity\Result\ActivityResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L297-L310)
Return type
[`Bitrix24\SDK\Services\CRM\Activity\Result\ActivitiesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Result/ActivitiesResult.php)

⚡️Batch methods:
  • `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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L373-L384)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Core/Result/UpdatedItemResult.php)| \ No newline at end of file +|`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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L297-L310)
Return type
[`Bitrix24\SDK\Services\CRM\Activity\Result\ActivitiesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L373-L384)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Product/Service/Product.php#L78-L88)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Product/Service/Product.php#L106-L116)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Product/Service/Product.php#L134-L137)
Return type
[`Bitrix24\SDK\Services\CRM\Product\Result\ProductResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Product/Service/Product.php#L153-L156)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Product/Service/Product.php#L177-L190)
Return type
[`Bitrix24\SDK\Services\CRM\Product\Result\ProductsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Product/Service/Product.php#L231-L242)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Lead/Service/Lead.php#L115-L126)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Lead/Service/Lead.php#L144-L154)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Lead/Service/Lead.php#L170-L173)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Lead/Service/Lead.php#L191-L194)
Return type
[`Bitrix24\SDK\Services\CRM\Lead\Result\LeadResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Lead/Service/Lead.php#L215-L228)
Return type
[`Bitrix24\SDK\Services\CRM\Lead\Result\LeadsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Lead/Service/Lead.php#L307-L319)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Item/Service/Item.php#L49-L60)
Return type
[`Bitrix24\SDK\Services\CRM\Item\Result\ItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Item/Service/Item.php#L79-L86)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Item/Service/Item.php#L103-L106)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Item/Service/Item.php#L121-L124)
Return type
[`Bitrix24\SDK\Services\CRM\Item\Result\ItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Item/Service/Item.php#L139-L153)
Return type
[`Bitrix24\SDK\Services\CRM\Item\Result\ItemsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Item/Service/Item.php#L168-L180)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Duplicates/Service/Duplicate.php#L52-L60)
Return type
[`Bitrix24\SDK\Services\CRM\Duplicates\Result\DuplicateResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Activity/Service/Activity.php#L46-L52)
Return type
[`Bitrix24\SDK\Services\Workflows\Activity\Result\AddedMessageToLogResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Activity/Service/Activity.php#L66-L69)
Return type
[`Bitrix24\SDK\Services\Workflows\Activity\Result\WorkflowActivitiesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Activity/Service/Activity.php#L96-L123)
Return type
[`Bitrix24\SDK\Services\Workflows\Activity\Result\AddedActivityResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Activity/Service/Activity.php#L138-L144)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Activity/Service/Activity.php#L171-L225)
Return type
[`Bitrix24\SDK\Services\Workflows\Activity\Result\UpdateActivityResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Template/Service/Template.php#L48-L63)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Template/Service/Template.php#L83-L118)
Return type
[``](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/)| +|`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/feature/390-prepare-publish-2-0/src/Services/Workflows/Template/Service/Template.php#L136-L141)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Template/Service/Template.php#L155-L168)
Return type
[`Bitrix24\SDK\Services\Workflows\Template\Result\WorkflowTemplatesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Robot/Service/Robot.php#L48-L69)
Return type
[`Bitrix24\SDK\Services\Workflows\Robot\Result\AddedRobotResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Robot/Service/Robot.php#L83-L86)
Return type
[`Bitrix24\SDK\Services\Workflows\Robot\Result\WorkflowRobotsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Robot/Service/Robot.php#L101-L107)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Robot/Service/Robot.php#L124-L166)
Return type
[`Bitrix24\SDK\Services\Workflows\Robot\Result\UpdateRobotResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Workflow/Service/Workflow.php#L43-L48)
Return type
[`Bitrix24\SDK\Services\Workflows\Workflow\Result\WorkflowKillResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Workflow/Service/Workflow.php#L61-L67)
Return type
[`Bitrix24\SDK\Services\Workflows\Workflow\Result\WorkflowTerminationResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Workflow/Service/Workflow.php#L83-L135)
Return type
[`Bitrix24\SDK\Services\Workflows\Workflow\Result\WorkflowInstanceStartResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Workflow/Service/Workflow.php#L150-L165)
Return type
[`Bitrix24\SDK\Services\Workflows\Workflow\Result\WorkflowInstancesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Task/Service/Task.php#L54-L62)
Return type
[`Bitrix24\SDK\Services\Workflows\Task\Result\WorkflowTaskCompleteResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Task/Service/Task.php#L124-L134)
Return type
[`Bitrix24\SDK\Services\Workflows\Task\Result\WorkflowTasksResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Event/Service/Event.php#L41-L55)
Return type
[`Bitrix24\SDK\Services\Workflows\Event\Result\EventSendResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/User/Service/User.php#L34-L37)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/User/Service/User.php#L50-L53)
Return type
[`Bitrix24\SDK\Services\User\Result\UserResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/User/Service/User.php#L68-L83)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/User/Service/User.php#L95-L107)
Return type
[`Bitrix24\SDK\Services\User\Result\UsersResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/User/Service/User.php#L120-L128)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/User/Service/User.php#L142-L145)
Return type
[`Bitrix24\SDK\Services\User\Result\UsersResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/User/Service/User.php#L54-L59)
Return type
[`Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/User/Service/User.php#L75-L80)
Return type
[`Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/User/Service/User.php#L97-L104)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\User\Result\VoximplantUserSettingsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/Url/Service/Url.php#L41-L44)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\Url\Result\VoximplantPagesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/Line/Service/Line.php#L41-L46)
Return type
[`Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/Line/Service/Line.php#L58-L61)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\Line\Result\VoximplantLinesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/Line/Service/Line.php#L75-L78)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\Line\Result\VoximplantLineIdResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/Line/Service/Line.php#L94-L99)
Return type
[`Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/TTS/Voices/Service/Voices.php#L43-L46)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\TTS\Voices\Result\VoximplantVoicesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/Sip/Service/Sip.php#L48-L51)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result\SipConnectorStatusResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/Sip/Service/Sip.php#L65-L80)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result\SipLineAddedResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/Sip/Service/Sip.php#L96-L101)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/Sip/Service/Sip.php#L116-L119)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result\SipLinesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/Sip/Service/Sip.php#L136-L141)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result\SipLineStatusResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/Sip/Service/Sip.php#L156-L191)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/InfoCall/Service/InfoCall.php#L47-L55)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\InfoCall\Result\VoximplantInfoCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/InfoCall/Service/InfoCall.php#L62-L69)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\InfoCall\Result\VoximplantInfoCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Call/Service/Call.php#L45-L67)
Return type
[`Bitrix24\SDK\Services\Telephony\Call\Result\TranscriptAttachedResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/ExternalCall/Service/ExternalCall.php#L87-L98)
Return type
[`Bitrix24\SDK\Services\Telephony\ExternalCall\Result\CallRecordFileUploadedResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/ExternalCall/Service/ExternalCall.php#L147-L179)
Return type
[`Bitrix24\SDK\Services\Telephony\ExternalCall\Result\ExternalCallRegisteredResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/ExternalCall/Service/ExternalCall.php#L211-L217)
Return type
[`Bitrix24\SDK\Services\Telephony\ExternalCall\Result\SearchCrmEntitiesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/ExternalCall/Service/ExternalCall.php#L276-L299)
Return type
[`Bitrix24\SDK\Services\Telephony\ExternalCall\Result\ExternalCallFinishedResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/ExternalCall/Service/ExternalCall.php#L315-L322)
Return type
[`Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/ExternalCall/Service/ExternalCall.php#L338-L345)
Return type
[`Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/ExternalLine/Service/ExternalLine.php#L47-L54)
Return type
[`Bitrix24\SDK\Services\Telephony\ExternalLine\Result\ExternalLineAddedResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/ExternalLine/Service/ExternalLine.php#L68-L73)
Return type
[`Bitrix24\SDK\Core\Result\EmptyResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/ExternalLine/Service/ExternalLine.php#L87-L90)
Return type
[`Bitrix24\SDK\Services\Telephony\ExternalLine\Result\ExternalLinesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IM/Notify/Service/Notify.php#L35-L55)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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 system notification|[`Bitrix24\SDK\Services\IM\Notify\Service\Notify::fromPersonal`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Services/IM/Notify/Service/Notify.php#L62-L82)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IM/Notify/Service/Notify.php#L89-L103)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IM/Notify/Service/Notify.php#L147-L158)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IM/Notify/Service/Notify.php#L165-L177)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IM/Notify/Service/Notify.php#L184-L196)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/UserConsent/Service/UserConsent.php#L33-L36)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/UserConsent/Service/UserConsentAgreement.php#L31-L34)
Return type
[`Bitrix24\SDK\Services\UserConsent\Result\UserConsentAgreementsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/UserConsent/Service/UserConsentAgreement.php#L46-L61)
Return type
[`Bitrix24\SDK\Services\UserConsent\Result\UserConsentAgreementTextResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IMOpenLines/Service/Network.php#L29-L39)
Return type
[`Bitrix24\SDK\Services\IMOpenLines\Result\JoinOpenLineResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IMOpenLines/Service/Network.php#L49-L71)
Return type
[`Bitrix24\SDK\Services\IMOpenLines\Result\AddedMessageItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Event.php#L37-L45)
Return type
[`Bitrix24\SDK\Services\Main\Result\EventListResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Event.php#L60-L76)
Return type
[`Bitrix24\SDK\Services\Main\Result\EventHandlerBindResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Event.php#L91-L103)
Return type
[`Bitrix24\SDK\Services\Main\Result\EventHandlerUnbindResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Event.php#L116-L119)
Return type
[`Bitrix24\SDK\Core\Response\Response`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Event.php#L133-L136)
Return type
[`Bitrix24\SDK\Services\Main\Result\EventHandlersResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/UserFieldType.php#L36-L49)
Return type
[`Bitrix24\SDK\Services\Placement\Result\RegisterUserTypeResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/UserFieldType.php#L63-L68)
Return type
[`Bitrix24\SDK\Services\Placement\Result\UserFieldTypesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/UserFieldType.php#L87-L100)
Return type
[`Bitrix24\SDK\Services\Placement\Result\RegisterUserTypeResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/UserFieldType.php#L116-L126)
Return type
[`Bitrix24\SDK\Services\Placement\Result\DeleteUserTypeResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/Placement.php#L33-L48)
Return type
[`Bitrix24\SDK\Services\Placement\Result\PlacementBindResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/Placement.php#L63-L74)
Return type
[`Bitrix24\SDK\Services\Placement\Result\PlacementUnbindResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/Placement.php#L89-L96)
Return type
[`Bitrix24\SDK\Services\Placement\Result\PlacementLocationCodesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/Placement.php#L110-L113)
Return type
[`Bitrix24\SDK\Services\Placement\Result\PlacementsLocationInformationResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Services/Placement/Result/PlacementsLocationInformationResult.php)| \ No newline at end of file diff --git a/docs/EN/documentation.md b/docs/EN/documentation.md index f1db542e..1cea59bd 100644 --- a/docs/EN/documentation.md +++ b/docs/EN/documentation.md @@ -2,4 +2,18 @@ bitrix24-php-sdk documentation ============================================= ## Authorisation -- use [incoming webhooks](Core/Auth/auth.md) +- 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/phpstan.neon.dist b/phpstan.neon.dist index c46a4832..1da108fb 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -2,9 +2,15 @@ parameters: level: 5 paths: - src/ + - tests/Unit/ - tests/Integration/Services/Telephony - tests/Integration/Services/User - - tests/Unit/ + - 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: diff --git a/phpunit.xml.dist b/phpunit.xml.dist index ceb84608..9976fd86 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -19,9 +19,21 @@ ./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/ diff --git a/rector.php b/rector.php index 15a6dad1..92873a08 100644 --- a/rector.php +++ b/rector.php @@ -13,8 +13,20 @@ __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') diff --git a/src/Attributes/Services/AttributesParser.php b/src/Attributes/Services/AttributesParser.php index 885ee7db..8c1911fd 100644 --- a/src/Attributes/Services/AttributesParser.php +++ b/src/Attributes/Services/AttributesParser.php @@ -54,6 +54,7 @@ public function getSupportedInSdkApiMethods(array $sdkClassNames, string $sdkBas // 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); @@ -62,7 +63,7 @@ public function getSupportedInSdkApiMethods(array $sdkClassNames, string $sdkBas } $supportedInSdkMethods[$instance->name] = [ - 'sdk_scope' => $apiServiceAttrInstance->scope->getScopeCodes()[0], + 'sdk_scope' => $apiServiceAttrInstance->scope->getScopeCodes() === [] ? '' : $apiServiceAttrInstance->scope->getScopeCodes()[0], 'name' => $instance->name, 'documentation_url' => $instance->documentationUrl, 'description' => $instance->description, @@ -73,6 +74,7 @@ public function getSupportedInSdkApiMethods(array $sdkClassNames, string $sdkBas '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 ]; diff --git a/src/Core/ApiLevelErrorHandler.php b/src/Core/ApiLevelErrorHandler.php index 1ce16ca2..0417c1d5 100644 --- a/src/Core/ApiLevelErrorHandler.php +++ b/src/Core/ApiLevelErrorHandler.php @@ -11,6 +11,7 @@ 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; @@ -118,6 +119,8 @@ private function handleError(array $responseBody, ?string $batchCommandId = null 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)); } diff --git a/src/Core/Exceptions/WrongAuthTypeException.php b/src/Core/Exceptions/WrongAuthTypeException.php new file mode 100644 index 00000000..b0126397 --- /dev/null +++ b/src/Core/Exceptions/WrongAuthTypeException.php @@ -0,0 +1,8 @@ +Return type
[`%s`](%s)%s|", - $apiMethod['sdk_scope'], + $apiMethod['sdk_scope'] === '' ? '–' : $apiMethod['sdk_scope'], $apiMethod['name'], $apiMethod['documentation_url'], $apiMethod['description'], @@ -178,6 +178,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int 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 diff --git a/src/Services/CRM/Activity/ReadModel/OpenLineFetcher.php b/src/Services/CRM/Activity/ReadModel/OpenLineFetcher.php index baa946be..bc753907 100644 --- a/src/Services/CRM/Activity/ReadModel/OpenLineFetcher.php +++ b/src/Services/CRM/Activity/ReadModel/OpenLineFetcher.php @@ -5,16 +5,21 @@ 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 \Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface $bulkItemsReader + * @param BulkItemsReaderInterface $bulkItemsReader */ public function __construct(BulkItemsReaderInterface $bulkItemsReader) { @@ -22,20 +27,19 @@ public function __construct(BulkItemsReaderInterface $bulkItemsReader) } /** - * @param array $order - * @param array $filter - * @param array $select - * @param int|null $openLineTypeId - * @param int|null $limit - * - * @return OpenLineActivityItemResult[]|Generator - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @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_ID' => 'IMOPENLINES_SESSION', 'PROVIDER_TYPE_ID' => $openLineTypeId, ]); } else { diff --git a/src/Services/CRM/Activity/ReadModel/VoximplantFetcher.php b/src/Services/CRM/Activity/ReadModel/VoximplantFetcher.php index 1ed02368..9143b2f9 100644 --- a/src/Services/CRM/Activity/ReadModel/VoximplantFetcher.php +++ b/src/Services/CRM/Activity/ReadModel/VoximplantFetcher.php @@ -5,16 +5,22 @@ 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 \Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface $bulkItemsReader + * @param BulkItemsReaderInterface $bulkItemsReader */ public function __construct(BulkItemsReaderInterface $bulkItemsReader) { @@ -22,18 +28,18 @@ public function __construct(BulkItemsReaderInterface $bulkItemsReader) } /** - * @param array $order - * @param array $filter - * @param array $select - * @param int|null $limit - * - * @return \Bitrix24\SDK\Services\CRM\Activity\Result\ActivityItemResult[]|Generator - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @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_ID' => 'VOXIMPLANT_CALL', 'PROVIDER_TYPE_ID' => 'CALL', ]); diff --git a/src/Services/CRM/Activity/ReadModel/WebFormFetcher.php b/src/Services/CRM/Activity/ReadModel/WebFormFetcher.php index 5d4c0662..78e22715 100644 --- a/src/Services/CRM/Activity/ReadModel/WebFormFetcher.php +++ b/src/Services/CRM/Activity/ReadModel/WebFormFetcher.php @@ -5,16 +5,22 @@ 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 \Bitrix24\SDK\Core\Contracts\BulkItemsReaderInterface $bulkItemsReader + * @param BulkItemsReaderInterface $bulkItemsReader */ public function __construct(BulkItemsReaderInterface $bulkItemsReader) { @@ -22,20 +28,20 @@ public function __construct(BulkItemsReaderInterface $bulkItemsReader) } /** - * @param array $order - * @param array $filter - * @param array $select - * @param int|null $webFormId - * @param int|null $limit + * @return Generator * - * @return WebFormActivityItemResult[]|Generator - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @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_ID' => 'CRM_WEBFORM', 'PROVIDER_TYPE_ID' => $webFormId, ]); } else { diff --git a/src/Services/CRM/Activity/Service/Activity.php b/src/Services/CRM/Activity/Service/Activity.php index 4124f0ff..5c9b9605 100644 --- a/src/Services/CRM/Activity/Service/Activity.php +++ b/src/Services/CRM/Activity/Service/Activity.php @@ -46,8 +46,8 @@ public function __construct(Batch $batch, CoreInterface $core, LoggerInterface $ * @param array{ * ID?: int, * OWNER_ID?: int, - * OWNER_TYPE_ID?: string, - * TYPE_ID?: string, + * OWNER_TYPE_ID?: int, + * TYPE_ID?: int, * PROVIDER_ID?: string, * PROVIDER_TYPE_ID?: string, * PROVIDER_GROUP_ID?: string, diff --git a/src/Services/CRM/Contact/Service/Batch.php b/src/Services/CRM/Contact/Service/Batch.php index 0d929947..58175335 100644 --- a/src/Services/CRM/Contact/Service/Batch.php +++ b/src/Services/CRM/Contact/Service/Batch.php @@ -4,6 +4,9 @@ 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; @@ -12,11 +15,7 @@ use Bitrix24\SDK\Services\CRM\Contact\Result\ContactItemResult; use Generator; -/** - * Class Batch - * - * @package Bitrix24\SDK\Services\CRM\Contact\Service - */ +#[ApiBatchServiceMetadata(new Scope(['crm']))] class Batch extends AbstractBatchService { /** @@ -127,6 +126,11 @@ class Batch extends AbstractBatchService * @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( @@ -196,8 +200,14 @@ public function list(array $order, array $filter, array $select, ?int $limit = n * IM?: string, * }> $contacts * - * @return Generator|AddedItemBatchResult[] + * @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 = []; @@ -221,9 +231,14 @@ public function add(array $contacts): Generator * ] * * @param array $entityItems - * @return Generator + * @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) { @@ -236,9 +251,14 @@ public function update(array $entityItems): Generator * * @param int[] $contactId * - * @return \Generator - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @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) { diff --git a/src/Services/CRM/Contact/Service/Contact.php b/src/Services/CRM/Contact/Service/Contact.php index 6776dac6..68e92ae0 100644 --- a/src/Services/CRM/Contact/Service/Contact.php +++ b/src/Services/CRM/Contact/Service/Contact.php @@ -4,7 +4,10 @@ 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; @@ -16,11 +19,7 @@ use Bitrix24\SDK\Services\CRM\Contact\Result\ContactsResult; use Psr\Log\LoggerInterface; -/** - * Class Contact - * - * @package Bitrix24\SDK\Services\CRM\Contact\Service - */ +#[ApiServiceMetadata(new Scope(['crm']))] class Contact extends AbstractService { public Batch $batch; @@ -28,8 +27,8 @@ class Contact extends AbstractService /** * Contact constructor. * - * @param Batch $batch - * @param CoreInterface $core + * @param Batch $batch + * @param CoreInterface $core * @param LoggerInterface $log */ public function __construct(Batch $batch, CoreInterface $core, LoggerInterface $log) @@ -101,6 +100,11 @@ public function __construct(Batch $batch, CoreInterface $core, LoggerInterface $ * @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( @@ -125,6 +129,11 @@ public function add(array $fields, array $params = ['REGISTER_SONET_EVENT' => 'N * @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( @@ -146,6 +155,11 @@ public function delete(int $contactId): DeletedItemResult * @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')); @@ -162,6 +176,11 @@ public function fields(): FieldsResult * @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( @@ -279,22 +298,27 @@ public function get(int $contactId): ContactResult * 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 + * @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, + 'order' => $order, 'filter' => $filter, 'select' => $select, - 'start' => $start, + 'start' => $start, ] ) ); @@ -360,13 +384,18 @@ public function list(array $order, array $filter, array $select, int $start): Co * @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, + 'id' => $contactId, 'fields' => $fields, 'params' => $params, ] diff --git a/src/Services/CRM/Contact/Service/ContactUserfield.php b/src/Services/CRM/Contact/Service/ContactUserfield.php index 4b873c17..7a36c4cb 100644 --- a/src/Services/CRM/Contact/Service/ContactUserfield.php +++ b/src/Services/CRM/Contact/Service/ContactUserfield.php @@ -4,6 +4,11 @@ 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; @@ -12,6 +17,7 @@ use Bitrix24\SDK\Services\CRM\Contact\Result\ContactUserfieldsResult; use Bitrix24\SDK\Services\CRM\Userfield\Exceptions\UserfieldNameIsTooLongException; +#[ApiServiceMetadata(new Scope(['crm']))] class ContactUserfield extends AbstractService { /** @@ -58,17 +64,22 @@ class ContactUserfield extends AbstractService * SETTINGS?: string, * } $filter * - * @return \Bitrix24\SDK\Services\CRM\Contact\Result\ContactUserfieldsResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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, + 'order' => $order, 'filter' => $filter, ] ) @@ -102,13 +113,18 @@ public function list(array $order, array $filter): ContactUserfieldsResult * SETTINGS?: string, * } $userfieldItemFields * - * @return \Bitrix24\SDK\Core\Result\AddedItemResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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) { @@ -137,11 +153,16 @@ public function add(array $userfieldItemFields): AddedItemResult * @param int $userfieldId * * @return \Bitrix24\SDK\Core\Result\DeletedItemResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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( @@ -159,11 +180,16 @@ public function delete(int $userfieldId): DeletedItemResult * * @param int $contactUserfieldItemId * - * @return \Bitrix24\SDK\Services\CRM\Contact\Result\ContactUserfieldResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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( @@ -179,21 +205,26 @@ public function get(int $contactUserfieldItemId): ContactUserfieldResult /** * Updates an existing user field for contacts. * - * @param int $contactUserfieldItemId + * @param int $contactUserfieldItemId * @param array $userfieldFieldsToUpdate * - * @return \Bitrix24\SDK\Core\Result\UpdatedItemResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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, + 'id' => $contactUserfieldItemId, 'fields' => $userfieldFieldsToUpdate, ] ) diff --git a/src/Services/CRM/Deal/Service/Batch.php b/src/Services/CRM/Deal/Service/Batch.php index c7234694..6a32e499 100644 --- a/src/Services/CRM/Deal/Service/Batch.php +++ b/src/Services/CRM/Deal/Service/Batch.php @@ -4,7 +4,10 @@ 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; @@ -13,11 +16,7 @@ use Generator; use Psr\Log\LoggerInterface; -/** - * Class Batch - * - * @package Bitrix24\SDK\Services\CRM\Deal\Service - */ +#[ApiBatchServiceMetadata(new Scope(['crm']))] class Batch { protected BatchOperationsInterface $batch; @@ -27,7 +26,7 @@ class Batch * Batch constructor. * * @param BatchOperationsInterface $batch - * @param LoggerInterface $log + * @param LoggerInterface $log */ public function __construct(BatchOperationsInterface $batch, LoggerInterface $log) { @@ -125,21 +124,26 @@ public function __construct(BatchOperationsInterface $batch, LoggerInterface $lo * UTM_CONTENT?: string, * UTM_TERM?: string, * } $filter - * @param array $select = ['ID','TITLE','TYPE_ID','CATEGORY_ID','STAGE_ID','STAGE_SEMANTIC_ID','IS_NEW','IS_RECURRING','IS_RETURN_CUSTOMER','IS_REPEATED_APPROACH','PROBABILITY','CURRENCY_ID','OPPORTUNITY','IS_MANUAL_OPPORTUNITY','TAX_VALUE','COMPANY_ID','CONTACT_ID','CONTACT_IDS','QUOTE_ID','BEGINDATE','CLOSEDATE','OPENED','CLOSED','COMMENTS','ASSIGNED_BY_ID','CREATED_BY_ID','MODIFY_BY_ID','DATE_CREATE','DATE_MODIFY','SOURCE_ID','SOURCE_DESCRIPTION','LEAD_ID','ADDITIONAL_INFO','LOCATION_ID','ORIGINATOR_ID','ORIGIN_ID','UTM_SOURCE','UTM_MEDIUM','UTM_CAMPAIGN','UTM_CONTENT','UTM_TERM'] - * @param int|null $limit + * @param array $select = ['ID','TITLE','TYPE_ID','CATEGORY_ID','STAGE_ID','STAGE_SEMANTIC_ID','IS_NEW','IS_RECURRING','IS_RETURN_CUSTOMER','IS_REPEATED_APPROACH','PROBABILITY','CURRENCY_ID','OPPORTUNITY','IS_MANUAL_OPPORTUNITY','TAX_VALUE','COMPANY_ID','CONTACT_ID','CONTACT_IDS','QUOTE_ID','BEGINDATE','CLOSEDATE','OPENED','CLOSED','COMMENTS','ASSIGNED_BY_ID','CREATED_BY_ID','MODIFY_BY_ID','DATE_CREATE','DATE_MODIFY','SOURCE_ID','SOURCE_DESCRIPTION','LEAD_ID','ADDITIONAL_INFO','LOCATION_ID','ORIGINATOR_ID','ORIGIN_ID','UTM_SOURCE','UTM_MEDIUM','UTM_CAMPAIGN','UTM_CONTENT','UTM_TERM'] + * @param int|null $limit * * @return Generator|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, + 'order' => $order, 'filter' => $filter, 'select' => $select, - 'limit' => $limit, + 'limit' => $limit, ] ); foreach ($this->batch->getTraversableList('crm.deal.list', $order, $filter, $select, $limit) as $key => $value) { @@ -194,9 +198,14 @@ public function list(array $order, array $filter, array $select, ?int $limit = n * UTM_TERM?: string, * }> $deals * - * @return Generator|AddedItemBatchResult[] - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @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 = []; @@ -215,9 +224,14 @@ public function add(array $deals): Generator * * @param int[] $dealId * - * @return \Generator|\Bitrix24\SDK\Core\Contracts\DeletedItemResultInterface[] - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @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) { @@ -234,11 +248,16 @@ public function delete(array $dealId): Generator * 'params' => [] * ] * - * @param array $entityItems + * @param array $entityItems * - * @return \Generator - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @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) { diff --git a/src/Services/CRM/Deal/Service/Deal.php b/src/Services/CRM/Deal/Service/Deal.php index 0e451728..12b07cd5 100644 --- a/src/Services/CRM/Deal/Service/Deal.php +++ b/src/Services/CRM/Deal/Service/Deal.php @@ -143,6 +143,11 @@ public function delete(int $id): DeletedItemResult * @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')); @@ -159,6 +164,11 @@ public function fields(): FieldsResult * @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])); @@ -178,6 +188,11 @@ public function get(int $id): DealResult * @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( @@ -245,6 +260,11 @@ public function list(array $order, array $filter, array $select, int $startItem * @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( @@ -301,8 +321,8 @@ public function update(int $id, array $fields, array $params = []): UpdatedItemR * } $filter * * @return int - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws BaseException + * @throws TransportException */ public function countByFilter(array $filter = []): int { diff --git a/src/Services/CRM/Deal/Service/DealCategory.php b/src/Services/CRM/Deal/Service/DealCategory.php index bdda858d..9497bfe8 100644 --- a/src/Services/CRM/Deal/Service/DealCategory.php +++ b/src/Services/CRM/Deal/Service/DealCategory.php @@ -4,6 +4,9 @@ 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; @@ -15,11 +18,7 @@ use Bitrix24\SDK\Services\CRM\Deal\Result\DealCategoryResult; use Bitrix24\SDK\Services\CRM\Deal\Result\DealCategoryStatusResult; -/** - * Class DealCategory - * - * @package Bitrix24\SDK\Services\CRM\Deal\Service - */ +#[ApiServiceMetadata(new Scope(['crm']))] class DealCategory extends AbstractService { /** @@ -39,6 +38,11 @@ class DealCategory extends AbstractService * @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( @@ -62,6 +66,11 @@ public function add(array $fields): AddedItemResult * @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( @@ -83,6 +92,11 @@ public function delete(int $categoryId): DeletedItemResult * @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')); @@ -96,6 +110,11 @@ public function fields(): FieldsResult * @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')); @@ -114,6 +133,11 @@ public function getDefaultCategorySettings(): DealCategoryResult * @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)); @@ -131,6 +155,11 @@ public function setDefaultCategorySettings(array $parameters): UpdatedItemResult * @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( @@ -151,22 +180,27 @@ public function get(int $categoryId): DealCategoryResult * @param array $order * @param array $filter * @param array $select - * @param int $start + * @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, + 'order' => $order, 'filter' => $filter, 'select' => $select, - 'start' => $start, + 'start' => $start, ] ) ); @@ -183,6 +217,11 @@ public function list(array $order, array $filter, array $select, int $start): De * @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( @@ -213,13 +252,18 @@ public function getStatus(int $categoryId): DealCategoryStatusResult * @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, + 'id' => $categoryId, 'fields' => $fields, ] ) diff --git a/src/Services/CRM/Deal/Service/DealCategoryStage.php b/src/Services/CRM/Deal/Service/DealCategoryStage.php index 5eb05e5d..6d608642 100644 --- a/src/Services/CRM/Deal/Service/DealCategoryStage.php +++ b/src/Services/CRM/Deal/Service/DealCategoryStage.php @@ -4,25 +4,28 @@ 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; -/** - * Class DealCategoryStage - * - * @package Bitrix24\SDK\Services\CRM\Deal\Service - */ +#[ApiServiceMetadata(new Scope(['crm']))] class DealCategoryStage extends AbstractService { /** - * @param int $categoryId + * @param int $categoryId Category ID. When ID = 0 or null is specified , returns "default" category statuses. When ID > 0 for nonexistent category , returns nothing. * - * @return DealCategoryStagesResult * @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( diff --git a/src/Services/CRM/Deal/Service/DealContact.php b/src/Services/CRM/Deal/Service/DealContact.php index c5c8a0f5..6f2ba9cd 100644 --- a/src/Services/CRM/Deal/Service/DealContact.php +++ b/src/Services/CRM/Deal/Service/DealContact.php @@ -4,6 +4,9 @@ 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; @@ -13,11 +16,7 @@ use Bitrix24\SDK\Services\AbstractService; use Bitrix24\SDK\Services\CRM\Deal\Result\DealContactItemsResult; -/** - * Class DealContact - * - * @package Bitrix24\SDK\Services\CRM\Deal\Service - */ +#[ApiServiceMetadata(new Scope(['crm']))] class DealContact extends AbstractService { /** @@ -25,15 +24,19 @@ class DealContact extends AbstractService * * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_contact_add.php * - * @param int $dealId - * @param int $contactId + * @param int $dealId + * @param int $contactId * @param bool $isPrimary - * @param int $sort + * @param int $sort * - * @return AddedItemResult - * @throws TransportException * @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( @@ -55,10 +58,14 @@ public function add(int $dealId, int $contactId, bool $isPrimary, int $sort = 10 * 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 - * @return FieldsResult * @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')); @@ -75,6 +82,11 @@ public function fields(): FieldsResult * @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( @@ -98,6 +110,11 @@ public function itemsGet(int $dealId): DealContactItemsResult * @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( @@ -126,6 +143,11 @@ public function itemsDelete(int $dealId): DeletedItemResult * @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( @@ -151,6 +173,11 @@ public function itemsSet(int $dealId, array $contactItems): UpdatedItemResult * @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( diff --git a/src/Services/CRM/Deal/Service/DealProductRows.php b/src/Services/CRM/Deal/Service/DealProductRows.php index 42cacb1d..c9855202 100644 --- a/src/Services/CRM/Deal/Service/DealProductRows.php +++ b/src/Services/CRM/Deal/Service/DealProductRows.php @@ -4,6 +4,9 @@ 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; @@ -12,11 +15,7 @@ use Bitrix24\SDK\Services\CRM\Deal\Result\DealResult; use Money\Currency; -/** - * Class DealProductRows - * - * @package Bitrix24\SDK\Services\CRM\Deals\Service - */ +#[ApiServiceMetadata(new Scope(['crm']))] class DealProductRows extends AbstractService { /** @@ -25,11 +24,15 @@ class DealProductRows extends AbstractService * @link https://training.bitrix24.com/rest_help/crm/deals/crm_deal_productrows_get.php * * @param int $dealId - * @param \Money\Currency|null $currency - * @return \Bitrix24\SDK\Services\CRM\Deal\Result\DealProductRowItemsResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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) { @@ -88,6 +91,11 @@ public function get(int $dealId, Currency $currency = null): DealProductRowItems * @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( diff --git a/src/Services/CRM/Deal/Service/DealUserfield.php b/src/Services/CRM/Deal/Service/DealUserfield.php index e250db76..74dc23ca 100644 --- a/src/Services/CRM/Deal/Service/DealUserfield.php +++ b/src/Services/CRM/Deal/Service/DealUserfield.php @@ -4,6 +4,11 @@ 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; @@ -11,7 +16,7 @@ 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 { /** @@ -61,10 +66,15 @@ class DealUserfield extends AbstractService * } $filter * * @return \Bitrix24\SDK\Services\CRM\Deal\Result\DealUserfieldsResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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( @@ -106,12 +116,17 @@ public function list(array $order, array $filter): DealUserfieldsResult * } $userfieldItemFields * * @return \Bitrix24\SDK\Core\Result\AddedItemResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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) { @@ -140,11 +155,16 @@ public function add(array $userfieldItemFields): AddedItemResult * @param int $userfieldId * * @return \Bitrix24\SDK\Core\Result\DeletedItemResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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( @@ -162,11 +182,16 @@ public function delete(int $userfieldId): DeletedItemResult * * @param int $userfieldItemId * - * @return \Bitrix24\SDK\Services\CRM\Deal\Result\DealUserfieldResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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( @@ -186,10 +211,15 @@ public function get(int $userfieldItemId): DealUserfieldResult * @param array $userfieldFieldsToUpdate * * @return \Bitrix24\SDK\Core\Result\UpdatedItemResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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( diff --git a/src/Services/CRM/Duplicates/Service/Duplicate.php b/src/Services/CRM/Duplicates/Service/Duplicate.php index 9b0b122d..a3c4bfc6 100644 --- a/src/Services/CRM/Duplicates/Service/Duplicate.php +++ b/src/Services/CRM/Duplicates/Service/Duplicate.php @@ -4,11 +4,15 @@ 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 { /** @@ -18,6 +22,11 @@ class Duplicate extends AbstractService * @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', @@ -35,6 +44,11 @@ public function findByPhone(array $phones, ?EntityType $entityType = null): mixe * @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', diff --git a/src/Services/CRM/Item/Service/Batch.php b/src/Services/CRM/Item/Service/Batch.php index 14ff222b..25bcc5c8 100644 --- a/src/Services/CRM/Item/Service/Batch.php +++ b/src/Services/CRM/Item/Service/Batch.php @@ -4,13 +4,17 @@ 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; @@ -28,6 +32,11 @@ public function __construct(BatchOperationsInterface $batch, LoggerInterface $lo * @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( @@ -48,10 +57,14 @@ public function list(int $entityTypeId, array $order, array $filter, array $sele /** * Batch adding crm items * - * @return Generator|ItemItemResult[] - * + * @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 = []; diff --git a/src/Services/CRM/Item/Service/Item.php b/src/Services/CRM/Item/Service/Item.php index f080641e..f257c9e0 100644 --- a/src/Services/CRM/Item/Service/Item.php +++ b/src/Services/CRM/Item/Service/Item.php @@ -4,7 +4,10 @@ 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; @@ -15,6 +18,7 @@ use Bitrix24\SDK\Services\CRM\Item\Result\ItemsResult; use Psr\Log\LoggerInterface; +#[ApiServiceMetadata(new Scope(['crm']))] class Item extends AbstractService { public Batch $batch; @@ -37,6 +41,11 @@ public function __construct(Batch $batch, CoreInterface $core, LoggerInterface $ * @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( @@ -62,6 +71,11 @@ public function add(int $entityTypeId, array $fields): ItemResult * @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( @@ -81,6 +95,11 @@ public function delete(int $entityTypeId, int $id): DeletedItemResult * @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])); @@ -94,6 +113,11 @@ public function fields(int $entityTypeId): FieldsResult * @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])); @@ -107,6 +131,11 @@ public function get(int $entityTypeId, int $id): ItemResult * @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( @@ -131,6 +160,11 @@ public function list(int $entityTypeId, array $order, array $filter, array $sele * @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( diff --git a/src/Services/CRM/Lead/Service/Batch.php b/src/Services/CRM/Lead/Service/Batch.php index e34bdbbb..fab4ab81 100644 --- a/src/Services/CRM/Lead/Service/Batch.php +++ b/src/Services/CRM/Lead/Service/Batch.php @@ -4,7 +4,10 @@ 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; @@ -12,11 +15,7 @@ use Generator; use Psr\Log\LoggerInterface; -/** - * Class Batch - * - * @package Bitrix24\SDK\Services\CRM\Lead\Service - */ +#[ApiBatchServiceMetadata(new Scope(['crm']))] class Batch { protected BatchOperationsInterface $batch; @@ -130,6 +129,11 @@ public function __construct(BatchOperationsInterface $batch, LoggerInterface $lo * @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( @@ -193,9 +197,14 @@ public function list(array $order, array $filter, array $select, ?int $limit = n * UTM_TERM?: string, * }> $leads * - * @return Generator|AddedItemBatchResult[] - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @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 = []; @@ -214,9 +223,14 @@ public function add(array $leads): Generator * * @param int[] $leadId * - * @return \Generator|\Bitrix24\SDK\Core\Contracts\DeletedItemResultInterface[] - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @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) { diff --git a/src/Services/CRM/Lead/Service/Lead.php b/src/Services/CRM/Lead/Service/Lead.php index 808a5b63..f2c67aa1 100644 --- a/src/Services/CRM/Lead/Service/Lead.php +++ b/src/Services/CRM/Lead/Service/Lead.php @@ -4,7 +4,10 @@ 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; @@ -15,7 +18,7 @@ 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; @@ -104,6 +107,11 @@ public function __construct(Batch $batch, CoreInterface $core, LoggerInterface $ * @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( @@ -128,6 +136,11 @@ public function add(array $fields, array $params = []): AddedItemResult * @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( @@ -149,6 +162,11 @@ public function delete(int $id): DeletedItemResult * @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')); @@ -165,6 +183,11 @@ public function fields(): FieldsResult * @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])); @@ -184,6 +207,11 @@ public function get(int $id): LeadResult * @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( @@ -271,6 +299,11 @@ public function list(array $order, array $filter, array $select, int $startItem * @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( diff --git a/src/Services/CRM/Product/Service/Batch.php b/src/Services/CRM/Product/Service/Batch.php index 5858aece..16c0fdb6 100644 --- a/src/Services/CRM/Product/Service/Batch.php +++ b/src/Services/CRM/Product/Service/Batch.php @@ -4,21 +4,20 @@ 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; -/** - * Class Batch - * - * @package Bitrix24\SDK\Services\CRM\Product\Service - */ +#[ApiBatchServiceMetadata(new Scope(['crm']))] class Batch extends AbstractBatchService { /** - * batch list method + * batch product list method * * @param array{ * ID?: string @@ -33,6 +32,11 @@ class Batch extends AbstractBatchService * @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( @@ -76,8 +80,13 @@ public function list(array $order, array $filter, array $select, ?int $limit = n * CREATED_BY?: int * }> $products * - * @return Generator|AddedItemBatchResult[] + * @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 = []; diff --git a/src/Services/CRM/Product/Service/Product.php b/src/Services/CRM/Product/Service/Product.php index 1a94f095..ddfb92a3 100644 --- a/src/Services/CRM/Product/Service/Product.php +++ b/src/Services/CRM/Product/Service/Product.php @@ -4,7 +4,10 @@ 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; @@ -16,11 +19,7 @@ use Bitrix24\SDK\Services\CRM\Product\Result\ProductsResult; use Psr\Log\LoggerInterface; -/** - * Class Product - * - * @package Bitrix24\SDK\Services\CRM\Product\Service - */ +#[ApiServiceMetadata(new Scope(['crm']))] class Product extends AbstractService { public Batch $batch; @@ -71,6 +70,11 @@ public function __construct(Batch $batch, CoreInterface $core, LoggerInterface $ * @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( @@ -90,10 +94,15 @@ public function add(array $fields): AddedItemResult * * @param int $productId * - * @return \Bitrix24\SDK\Core\Result\DeletedItemResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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( @@ -113,10 +122,15 @@ public function delete(int $productId): DeletedItemResult * * @param int $id * - * @return \Bitrix24\SDK\Services\CRM\Product\Result\ProductResult + * @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])); @@ -131,6 +145,11 @@ public function get(int $id): ProductResult * @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')); @@ -150,6 +169,11 @@ public function fields(): FieldsResult * @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( @@ -199,6 +223,11 @@ public function list(array $order, array $filter, array $select, int $startItem * @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( @@ -240,8 +269,8 @@ public function update(int $id, array $fields): UpdatedItemResult * } $filter * * @return int - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws BaseException + * @throws TransportException */ public function countByFilter(array $filter = []): int { diff --git a/src/Services/CRM/Settings/Service/Settings.php b/src/Services/CRM/Settings/Service/Settings.php index 016acb63..7f164be3 100644 --- a/src/Services/CRM/Settings/Service/Settings.php +++ b/src/Services/CRM/Settings/Service/Settings.php @@ -4,16 +4,15 @@ 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; -/** - * Class Settings - * - * @package Bitrix24\SDK\Services\CRM\Settings\Service - */ +#[ApiServiceMetadata(new Scope(['crm']))] class Settings extends AbstractService { /** @@ -21,6 +20,11 @@ class Settings extends AbstractService * @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')); diff --git a/src/Services/CRM/Userfield/Service/Userfield.php b/src/Services/CRM/Userfield/Service/Userfield.php index 8f436efb..3caee0e8 100644 --- a/src/Services/CRM/Userfield/Service/Userfield.php +++ b/src/Services/CRM/Userfield/Service/Userfield.php @@ -9,7 +9,11 @@ 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 { /** @@ -20,6 +24,11 @@ class Userfield extends AbstractService * @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')); @@ -33,6 +42,11 @@ public function types(): UserfieldTypesResult * @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')); @@ -46,6 +60,11 @@ public function fields(): 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')); diff --git a/src/Services/Catalog/Catalog/Service/Catalog.php b/src/Services/Catalog/Catalog/Service/Catalog.php index ece3d4b2..bf15208f 100644 --- a/src/Services/Catalog/Catalog/Service/Catalog.php +++ b/src/Services/Catalog/Catalog/Service/Catalog.php @@ -20,8 +20,6 @@ class Catalog extends AbstractService /** * The method gets field values of commercial catalog by ID. * - * @param int $catalogId - * @return CatalogResult * @throws BaseException * @throws TransportException * @see https://training.bitrix24.com/rest_help/catalog/catalog/catalog_catalog_get.php @@ -40,11 +38,6 @@ public function get(int $catalogId): CatalogResult * The method gets field value of commercial catalog product list * * @see https://training.bitrix24.com/rest_help/catalog/catalog/catalog_catalog_list.php - * @param array $select - * @param array $filter - * @param array $order - * @param int $start - * @return CatalogsResult * @throws BaseException * @throws TransportException */ diff --git a/src/Services/Catalog/Common/Result/AbstractCatalogItem.php b/src/Services/Catalog/Common/Result/AbstractCatalogItem.php index 6f4bed8d..25260f7d 100644 --- a/src/Services/Catalog/Common/Result/AbstractCatalogItem.php +++ b/src/Services/Catalog/Common/Result/AbstractCatalogItem.php @@ -14,15 +14,12 @@ abstract class AbstractCatalogItem extends AbstractItem { private const CRM_USERFIELD_PREFIX = 'UF_CRM_'; - /** - * @var Currency - */ private Currency $currency; public function __construct(array $data, Currency $currency = null) { parent::__construct($data); - if ($currency !== null) { + if ($currency instanceof Currency) { $this->currency = $currency; } } @@ -45,6 +42,7 @@ public function __get($offset) if ($this->data[$offset] !== null) { return $this->data[$offset] === 'Y'; } + return null; case 'code': case 'detailText': @@ -65,6 +63,7 @@ public function __get($offset) if ($this->data[$offset] !== '' && $this->data[$offset] !== null) { return (int)$this->data[$offset]; } + break; case 'dateActiveFrom': case 'dateActiveTo': @@ -85,7 +84,6 @@ public function __get($offset) /** * get userfield by field name * - * @param string $fieldName * * @return mixed|null * @throws UserfieldNotFoundException @@ -95,6 +93,7 @@ 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)); } diff --git a/src/Services/Catalog/Product/Result/ProductResult.php b/src/Services/Catalog/Product/Result/ProductResult.php index e9aef70e..9063e818 100644 --- a/src/Services/Catalog/Product/Result/ProductResult.php +++ b/src/Services/Catalog/Product/Result/ProductResult.php @@ -14,6 +14,7 @@ public function product(): ProductItemResult // 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/Service/Product.php b/src/Services/Catalog/Product/Service/Product.php index 372553d3..75b38cc6 100644 --- a/src/Services/Catalog/Product/Service/Product.php +++ b/src/Services/Catalog/Product/Service/Product.php @@ -22,16 +22,13 @@ #[ApiServiceMetadata(new Scope(['catalog']))] class Product extends AbstractService { - public Batch $batch; - public function __construct( - Batch $batch, + public Batch $batch, CoreInterface $core, - LoggerInterface $log + LoggerInterface $logger ) { - parent::__construct($core, $log); - $this->batch = $batch; + parent::__construct($core, $logger); } /** @@ -55,8 +52,6 @@ public function get(int $productId): ProductResult * The method adds a commercial catalog product. * * @see https://training.bitrix24.com/rest_help/catalog/product/catalog_product_add.php - * @param array $productFields - * @return ProductResult * @throws BaseException * @throws TransportException */ @@ -77,8 +72,6 @@ public function add(array $productFields): ProductResult * The method deletes commercial catalog product. * * @see https://training.bitrix24.com/rest_help/catalog/product/catalog_product_delete.php - * @param int $productId - * @return DeletedItemResult * @throws BaseException * @throws TransportException */ @@ -118,10 +111,6 @@ public function list(array $select, array $filter, array $order, int $start): Pr * The method returns commercial catalog product fields by filter. * @see https://training.bitrix24.com/rest_help/catalog/product/catalog_product_getfieldsbyfilter.php * - * @param int $iblockId - * @param ProductType $productType - * @param array|null $additionalFilter - * @return FieldsResult * @throws BaseException * @throws TransportException */ diff --git a/src/Services/IM/IMServiceBuilder.php b/src/Services/IM/IMServiceBuilder.php index 839ec8ed..d4a1d1e8 100644 --- a/src/Services/IM/IMServiceBuilder.php +++ b/src/Services/IM/IMServiceBuilder.php @@ -5,22 +5,14 @@ namespace Bitrix24\SDK\Services\IM; use Bitrix24\SDK\Services\AbstractServiceBuilder; -use Bitrix24\SDK\Services\IM\Service\IM; +use Bitrix24\SDK\Services\IM\Notify\Service\Notify; -/** - * Class IMServiceBuilder - * - * @package Bitrix24\SDK\Services\IM - */ class IMServiceBuilder extends AbstractServiceBuilder { - /** - * @return IM - */ - public function IM(): IM + public function notify(): Notify { if (!isset($this->serviceCache[__METHOD__])) { - $this->serviceCache[__METHOD__] = new IM($this->core, $this->log); + $this->serviceCache[__METHOD__] = new Notify($this->core, $this->log); } return $this->serviceCache[__METHOD__]; diff --git a/src/Services/IM/Notify/Service/Notify.php b/src/Services/IM/Notify/Service/Notify.php new file mode 100644 index 00000000..c2c36c75 --- /dev/null +++ b/src/Services/IM/Notify/Service/Notify.php @@ -0,0 +1,197 @@ +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/IM/Service/IM.php b/src/Services/IM/Service/IM.php deleted file mode 100644 index bd1ca645..00000000 --- a/src/Services/IM/Service/IM.php +++ /dev/null @@ -1,83 +0,0 @@ -log->debug( - 'notifyFromSystem.start', - [ - 'to' => $userId, - 'message' => $message, - ] - ); - - $result = $this->core->call( - 'im.notify', - [ - 'to' => $userId, - 'message' => $message, - 'type' => 'SYSTEM', - ] - ); - - $this->log->debug('notifyFromSystem.finish'); - - return $result; - } - - /** - * @param int $userId - * @param string $message - * - * @return Response - * @throws BaseException - * @throws TransportException - */ - public function notifyFromUser(int $userId, string $message): Response - { - $this->log->debug( - 'notifyFromUser.start', - [ - 'to' => $userId, - 'message' => $message, - ] - ); - - $result = $this->core->call( - 'im.notify', - [ - 'to' => $userId, - 'message' => $message, - 'type' => 'USER', - ] - ); - - $this->log->debug('notifyFromUser.finish'); - - return $result; - } -} \ No newline at end of file diff --git a/src/Services/IMOpenLines/IMOpenLinesServiceBuilder.php b/src/Services/IMOpenLines/IMOpenLinesServiceBuilder.php index e5e198b8..5643d5eb 100644 --- a/src/Services/IMOpenLines/IMOpenLinesServiceBuilder.php +++ b/src/Services/IMOpenLines/IMOpenLinesServiceBuilder.php @@ -9,9 +9,6 @@ class IMOpenLinesServiceBuilder extends AbstractServiceBuilder { - /** - * @return \Bitrix24\SDK\Services\IMOpenLines\Service\Network - */ public function Network(): Network { if (!isset($this->serviceCache[__METHOD__])) { diff --git a/src/Services/IMOpenLines/Result/AddedMessageItemResult.php b/src/Services/IMOpenLines/Result/AddedMessageItemResult.php index c9683cc1..9be1af30 100644 --- a/src/Services/IMOpenLines/Result/AddedMessageItemResult.php +++ b/src/Services/IMOpenLines/Result/AddedMessageItemResult.php @@ -11,7 +11,6 @@ class AddedMessageItemResult extends AbstractResult { /** - * @return bool * @throws BaseException */ public function isSuccess(): bool diff --git a/src/Services/IMOpenLines/Result/JoinOpenLineResult.php b/src/Services/IMOpenLines/Result/JoinOpenLineResult.php index 516824ef..0e61a5be 100644 --- a/src/Services/IMOpenLines/Result/JoinOpenLineResult.php +++ b/src/Services/IMOpenLines/Result/JoinOpenLineResult.php @@ -10,7 +10,6 @@ class JoinOpenLineResult extends AbstractResult implements AddedItemIdResultInterface { /** - * @return int * @throws \Bitrix24\SDK\Core\Exceptions\BaseException */ public function getId(): int diff --git a/src/Services/IMOpenLines/Service/Network.php b/src/Services/IMOpenLines/Service/Network.php index b99fdfca..2a9b0201 100644 --- a/src/Services/IMOpenLines/Service/Network.php +++ b/src/Services/IMOpenLines/Service/Network.php @@ -4,22 +4,28 @@ 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 { /** - * Connecting an open channel by code - * - * @param string $openLineCode - * - * @return \Bitrix24\SDK\Services\IMOpenLines\Result\JoinOpenLineResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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( @@ -33,37 +39,32 @@ public function join(string $openLineCode): JoinOpenLineResult } /** - * Sending Open Channel message to selected user - * - * @param string $openLineCode - * @param int $recipientUserId - * @param string $message - * @param bool $isMakeUrlPreview - * @param array|null $attach - * @param array|null $keyboard - * - * @return AddedMessageItemResult * @link https://training.bitrix24.com/support/training/course/?COURSE_ID=115&LESSON_ID=25018&LESSON_PATH=9691.9833.20331.25014.25018 - * */ + #[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, + int $recipientUserId, string $message, - bool $isMakeUrlPreview = true, + bool $isMakeUrlPreview = true, ?array $attach = null, ?array $keyboard = null - ): AddedMessageItemResult { + ): AddedMessageItemResult + { return new AddedMessageItemResult( $this->core->call( 'imopenlines.network.message.add', [ - 'CODE' => $openLineCode, - 'USER_ID' => $recipientUserId, - 'MESSAGE' => $message, + 'CODE' => $openLineCode, + 'USER_ID' => $recipientUserId, + 'MESSAGE' => $message, 'URL_PREVIEW' => $isMakeUrlPreview ? 'Y' : 'N', - 'ATTACH' => $attach, - 'KEYBOARD' => $keyboard, + 'ATTACH' => $attach, + 'KEYBOARD' => $keyboard, ] ) ); diff --git a/src/Services/Main/MainServiceBuilder.php b/src/Services/Main/MainServiceBuilder.php index 6a4f525b..0b278032 100644 --- a/src/Services/Main/MainServiceBuilder.php +++ b/src/Services/Main/MainServiceBuilder.php @@ -16,9 +16,6 @@ */ class MainServiceBuilder extends AbstractServiceBuilder { - /** - * @return Main - */ public function main(): Main { if (!isset($this->serviceCache[__METHOD__])) { @@ -28,9 +25,6 @@ public function main(): Main return $this->serviceCache[__METHOD__]; } - /** - * @return Event - */ public function event(): Event { if (!isset($this->serviceCache[__METHOD__])) { diff --git a/src/Services/Main/Result/EventHandlerBindResult.php b/src/Services/Main/Result/EventHandlerBindResult.php index bf511882..69de0c5a 100644 --- a/src/Services/Main/Result/EventHandlerBindResult.php +++ b/src/Services/Main/Result/EventHandlerBindResult.php @@ -10,7 +10,6 @@ class EventHandlerBindResult extends AbstractResult { /** - * @return bool * @throws BaseException */ public function isBinded(): bool diff --git a/src/Services/Main/Result/EventHandlerUnbindResult.php b/src/Services/Main/Result/EventHandlerUnbindResult.php index 47aa9136..35db152e 100644 --- a/src/Services/Main/Result/EventHandlerUnbindResult.php +++ b/src/Services/Main/Result/EventHandlerUnbindResult.php @@ -10,7 +10,6 @@ class EventHandlerUnbindResult extends AbstractResult { /** - * @return int * @throws BaseException */ public function getUnbindedHandlersCount(): int diff --git a/src/Services/Main/Result/EventListResult.php b/src/Services/Main/Result/EventListResult.php index 695cf217..83a87a35 100644 --- a/src/Services/Main/Result/EventListResult.php +++ b/src/Services/Main/Result/EventListResult.php @@ -10,7 +10,6 @@ class EventListResult extends AbstractResult { /** - * @return array * @throws BaseException */ public function getEvents(): array diff --git a/src/Services/Main/Result/IsUserAdminResult.php b/src/Services/Main/Result/IsUserAdminResult.php index 1bee191b..ef08fedd 100644 --- a/src/Services/Main/Result/IsUserAdminResult.php +++ b/src/Services/Main/Result/IsUserAdminResult.php @@ -10,7 +10,6 @@ class IsUserAdminResult extends AbstractResult { /** - * @return bool * @throws BaseException */ public function isAdmin(): bool diff --git a/src/Services/Main/Result/MethodAffordabilityResult.php b/src/Services/Main/Result/MethodAffordabilityResult.php index ad64373c..b4e2d068 100644 --- a/src/Services/Main/Result/MethodAffordabilityResult.php +++ b/src/Services/Main/Result/MethodAffordabilityResult.php @@ -10,7 +10,6 @@ class MethodAffordabilityResult extends AbstractResult { /** - * @return bool * @throws \Bitrix24\SDK\Core\Exceptions\BaseException */ public function isExisting(): bool @@ -19,7 +18,6 @@ public function isExisting(): bool } /** - * @return bool * @throws \Bitrix24\SDK\Core\Exceptions\BaseException */ public function isAvailable(): bool diff --git a/src/Services/Main/Result/ServerTimeResult.php b/src/Services/Main/Result/ServerTimeResult.php index 8a3c1e81..20c77c8c 100644 --- a/src/Services/Main/Result/ServerTimeResult.php +++ b/src/Services/Main/Result/ServerTimeResult.php @@ -12,7 +12,6 @@ class ServerTimeResult extends AbstractResult { /** - * @return CarbonImmutable * @throws BaseException * @throws Exception */ diff --git a/src/Services/Main/Result/UserProfileItemResult.php b/src/Services/Main/Result/UserProfileItemResult.php index d5bc4938..46bbbf90 100644 --- a/src/Services/Main/Result/UserProfileItemResult.php +++ b/src/Services/Main/Result/UserProfileItemResult.php @@ -29,6 +29,7 @@ public function __get($offset) if ($this->data[$offset] !== '' && $this->data[$offset] !== null) { return (int)$this->data[$offset]; } + return null; default: return parent::__get($offset); diff --git a/src/Services/Main/Service/Event.php b/src/Services/Main/Service/Event.php index cf5d2fa6..d8ffdb6a 100644 --- a/src/Services/Main/Service/Event.php +++ b/src/Services/Main/Service/Event.php @@ -4,7 +4,12 @@ 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; @@ -12,19 +17,23 @@ 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. * - * @param string|null $scopeCode * - * @return EventListResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException - * @throws \Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException + * @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( @@ -38,26 +47,27 @@ public function list(?string $scopeCode = null): EventListResult /** * Installs a new event handler. * - * @param string $eventCode - * @param string $handlerUrl - * @param int|null $userId - * @param array|null $options * - * @return \Bitrix24\SDK\Services\Main\Result\EventHandlerBindResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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' => $eventCode, + 'handler' => $handlerUrl, 'event_type ' => 'online', ]; if ($userId !== null) { $params['auth_type'] = $userId; } + if (is_array($options)) { $params = array_merge($params, $options); } @@ -68,20 +78,21 @@ public function bind(string $eventCode, string $handlerUrl, ?int $userId = null, /** * Uninstalls a previously installed event handler. * - * @param string $eventCode - * @param string $handlerUrl - * @param int|null $userId * - * @return \Bitrix24\SDK\Services\Main\Result\EventHandlerUnbindResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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' => $eventCode, + 'handler' => $handlerUrl, 'event_type ' => 'online', ]; if ($userId !== null) { @@ -92,13 +103,16 @@ public function unbind(string $eventCode, string $handlerUrl, ?int $userId = nul } /** - * @param array $payload * - * @return \Bitrix24\SDK\Core\Response\Response - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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); @@ -107,11 +121,15 @@ public function test(array $payload = []): Response /** * Obtaining a list of registered event handlers. * - * @return \Bitrix24\SDK\Services\Main\Result\EventHandlersResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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')); diff --git a/src/Services/Main/Service/EventManager.php b/src/Services/Main/Service/EventManager.php index af2cbe58..ffa74633 100644 --- a/src/Services/Main/Service/EventManager.php +++ b/src/Services/Main/Service/EventManager.php @@ -20,7 +20,6 @@ public function __construct( /** * @param EventHandlerMetadata[] $eventHandlerMetadata - * @return void * @throws InvalidArgumentException */ public function bindEventHandlers(array $eventHandlerMetadata): void @@ -31,6 +30,7 @@ public function bindEventHandlers(array $eventHandlerMetadata): void 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, @@ -44,13 +44,13 @@ public function bindEventHandlers(array $eventHandlerMetadata): void $alreadyInstalledHandlers = $this->eventService->get()->getEventHandlers(); foreach ($eventHandlerMetadata as $eventHandler) { $isInstalled = false; - foreach ($alreadyInstalledHandlers as $installedHandler) { + foreach ($alreadyInstalledHandlers as $alreadyInstalledHandler) { $this->logger->debug('bindEventHandlers.isHandlerInstalled', [ 'handlerToInstallCode' => $eventHandler->code, 'handlerToInstallUrl' => $eventHandler->handlerUrl, - 'isInstalled' => $eventHandler->isInstalled($installedHandler) + 'isInstalled' => $eventHandler->isInstalled($alreadyInstalledHandler) ]); - if ($eventHandler->isInstalled($installedHandler)) { + if ($eventHandler->isInstalled($alreadyInstalledHandler)) { $this->logger->debug('bindEventHandlers.handlerAlreadyInstalled', [ 'code' => $eventHandler->code, 'handlerUrl' => $eventHandler->handlerUrl @@ -60,6 +60,7 @@ public function bindEventHandlers(array $eventHandlerMetadata): void break; } } + if (!$isInstalled) { $toInstall[] = $eventHandler; $this->logger->debug('bindEventHandlers.handlerAddedToInstallPlan', [ @@ -86,23 +87,24 @@ public function bindEventHandlers(array $eventHandlerMetadata): void public function unbindAllEventHandlers(): EventHandlersResult { - $activeHandlers = $this->eventService->get(); - if (count($activeHandlers->getEventHandlers()) === 0) { - return $activeHandlers; + $eventHandlersResult = $this->eventService->get(); + if ($eventHandlersResult->getEventHandlers() === []) { + return $eventHandlersResult; } - $handlersToUnbind = $activeHandlers->getEventHandlers(); + $handlersToUnbind = $eventHandlersResult->getEventHandlers(); // todo replace to batch call - foreach ($handlersToUnbind as $itemHandler) { + foreach ($handlersToUnbind as $handlerToUnbind) { $this->logger->debug('unbindAllEventHandlers.handler', [ - 'code' => $itemHandler->event, - 'handler' => $itemHandler->handler, + 'code' => $handlerToUnbind->event, + 'handler' => $handlerToUnbind->handler, ]); $this->eventService->unbind( - $itemHandler->event, - $itemHandler->handler + $handlerToUnbind->event, + $handlerToUnbind->handler ); } - return $activeHandlers; + + return $eventHandlersResult; } } \ No newline at end of file diff --git a/src/Services/Main/Service/Main.php b/src/Services/Main/Service/Main.php index 7d4bd720..215a2d9b 100644 --- a/src/Services/Main/Service/Main.php +++ b/src/Services/Main/Service/Main.php @@ -4,6 +4,9 @@ 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; @@ -14,21 +17,21 @@ use Bitrix24\SDK\Services\Main\Result\ServerTimeResult; use Bitrix24\SDK\Services\Main\Result\UserProfileResult; -/** - * Class Main - * - * @package Bitrix24\SDK\Services - */ +#[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 - * @return \Bitrix24\SDK\Services\Main\Result\ServerTimeResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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')); @@ -38,10 +41,14 @@ public function getServerTime(): ServerTimeResult * Allows to return basic Information about the current user without any scopes, in contrast to user.current. * * @link https://training.bitrix24.com/rest_help/general/profile.php - * @return \Bitrix24\SDK\Services\Main\Result\UserProfileResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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')); @@ -50,13 +57,16 @@ public function getCurrentUserProfile(): UserProfileResult /** * Returns access permission names. * - * @param array $accessList * - * @return \Bitrix24\SDK\Core\Response\Response - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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', [ @@ -67,13 +77,16 @@ public function getAccessName(array $accessList): Response /** * Checks if the current user has at least one permission of those specified by the ACCESS parameter. * - * @param array $accessToCheck * - * @return \Bitrix24\SDK\Core\Response\Response - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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', [ @@ -84,13 +97,16 @@ public function checkUserAccess(array $accessToCheck): Response /** * Method returns 2 parameters - isExisting and isAvailable * - * @param string $methodName * - * @return \Bitrix24\SDK\Services\Main\Result\MethodAffordabilityResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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( @@ -103,11 +119,15 @@ public function getMethodAffordability(string $methodName): MethodAffordabilityR /** * It will return permissions available to the current application. * - * @return Response * @throws BaseException * @throws TransportException * @link https://training.bitrix24.com/rest_help/general/scope.php */ + #[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'); @@ -116,11 +136,15 @@ public function getCurrentScope(): Response /** * Method will return a list of all possible permissions. * - * @return Response * @throws BaseException * @throws TransportException * @link https://training.bitrix24.com/rest_help/general/scope.php */ + #[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]); @@ -129,12 +153,16 @@ public function getAvailableScope(): Response /** * Returns the methods available to the current application * - * @return Response * @throws BaseException * @throws TransportException * @deprecated use method.get * @link https://training.bitrix24.com/rest_help/general/methods.php */ + #[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', []); @@ -143,12 +171,16 @@ public function getAvailableMethods(): Response /** * Returns the methods available * - * @return Response * @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]); @@ -157,14 +189,17 @@ public function getAllMethods(): Response /** * Returns the methods available to the current application * - * @param string $scope * - * @return Response * @throws BaseException * @throws TransportException * @deprecated use method.get * @link https://training.bitrix24.com/rest_help/general/methods.php */ + #[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]); @@ -173,11 +208,15 @@ public function getMethodsByScope(string $scope): Response /** * Displays application information. The method supports secure calling convention. * - * @return ApplicationInfoResult * @throws BaseException * @throws TransportException * @link https://training.bitrix24.com/rest_help/general/app_info.php */ + #[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')); @@ -186,11 +225,15 @@ public function getApplicationInfo(): ApplicationInfoResult /** * Checks if a current user has permissions to manage application parameters. * - * @return IsUserAdminResult * @throws BaseException * @throws TransportException * @link https://training.bitrix24.com/rest_help/general/user_admin.php */ + #[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')); diff --git a/src/Services/Placement/PlacementServiceBuilder.php b/src/Services/Placement/PlacementServiceBuilder.php index 22b838be..f06d86bd 100644 --- a/src/Services/Placement/PlacementServiceBuilder.php +++ b/src/Services/Placement/PlacementServiceBuilder.php @@ -10,9 +10,6 @@ class PlacementServiceBuilder extends AbstractServiceBuilder { - /** - * @return Placement - */ public function placement(): Placement { if (!isset($this->serviceCache[__METHOD__])) { @@ -22,9 +19,6 @@ public function placement(): Placement return $this->serviceCache[__METHOD__]; } - /** - * @return \Bitrix24\SDK\Services\Placement\Service\UserFieldType - */ public function userfieldtype(): UserFieldType { if (!isset($this->serviceCache[__METHOD__])) { diff --git a/src/Services/Placement/Result/DeleteUserTypeResult.php b/src/Services/Placement/Result/DeleteUserTypeResult.php index 66cfb1ce..8714d0d4 100644 --- a/src/Services/Placement/Result/DeleteUserTypeResult.php +++ b/src/Services/Placement/Result/DeleteUserTypeResult.php @@ -10,7 +10,6 @@ class DeleteUserTypeResult extends AbstractResult { /** - * @return bool * @throws BaseException */ public function isSuccess(): bool diff --git a/src/Services/Placement/Result/PlacementBindResult.php b/src/Services/Placement/Result/PlacementBindResult.php index 4dfa0ddd..37bd628e 100644 --- a/src/Services/Placement/Result/PlacementBindResult.php +++ b/src/Services/Placement/Result/PlacementBindResult.php @@ -10,7 +10,6 @@ class PlacementBindResult extends AbstractResult { /** - * @return bool * @throws BaseException */ public function isSuccess(): bool diff --git a/src/Services/Placement/Result/PlacementLocationCodesResult.php b/src/Services/Placement/Result/PlacementLocationCodesResult.php index 0804042b..cc71af30 100644 --- a/src/Services/Placement/Result/PlacementLocationCodesResult.php +++ b/src/Services/Placement/Result/PlacementLocationCodesResult.php @@ -9,7 +9,6 @@ class PlacementLocationCodesResult extends AbstractResult { /** - * @return array * @throws \Bitrix24\SDK\Core\Exceptions\BaseException */ public function getLocationCodes(): array diff --git a/src/Services/Placement/Result/PlacementUnbindResult.php b/src/Services/Placement/Result/PlacementUnbindResult.php index 51dd7e51..0c882534 100644 --- a/src/Services/Placement/Result/PlacementUnbindResult.php +++ b/src/Services/Placement/Result/PlacementUnbindResult.php @@ -10,7 +10,6 @@ class PlacementUnbindResult extends AbstractResult { /** - * @return int * @throws BaseException */ public function getDeletedPlacementHandlersCount(): int diff --git a/src/Services/Placement/Result/RegisterUserTypeResult.php b/src/Services/Placement/Result/RegisterUserTypeResult.php index 2a0c6baf..33f7f268 100644 --- a/src/Services/Placement/Result/RegisterUserTypeResult.php +++ b/src/Services/Placement/Result/RegisterUserTypeResult.php @@ -10,7 +10,6 @@ class RegisterUserTypeResult extends AbstractResult { /** - * @return bool * @throws BaseException */ public function isSuccess(): bool diff --git a/src/Services/Placement/Service/Placement.php b/src/Services/Placement/Service/Placement.php index f27fd63f..a364925e 100644 --- a/src/Services/Placement/Service/Placement.php +++ b/src/Services/Placement/Service/Placement.php @@ -4,26 +4,32 @@ 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 * - * @param string $placementCode - * @param string $handlerUrl - * @param array $lang * - * @return \Bitrix24\SDK\Services\Placement\Result\PlacementBindResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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( @@ -41,14 +47,15 @@ public function bind(string $placementCode, string $handlerUrl, array $lang): Pl /** * Deletes the registered embedding location handler. Shall be executed with the available account administrative privileges. * - * @param string $placementCode - * @param string|null $handlerUrl - * - * @return \Bitrix24\SDK\Services\Placement\Result\PlacementUnbindResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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( @@ -65,13 +72,15 @@ public function unbind(string $placementCode, ?string $handlerUrl = null): Place /** * This method is used to retrieve the list of embedding locations, available to the application. * - * @param string|null $applicationScopeCode - * - * @return PlacementLocationCodesResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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( @@ -84,11 +93,15 @@ public function list(?string $applicationScopeCode = null): PlacementLocationCod /** * This method is used to retrieve the list of registered handlers for embedding locations. * - * @return PlacementsLocationInformationResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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')); diff --git a/src/Services/Placement/Service/PlacementLocationCode.php b/src/Services/Placement/Service/PlacementLocationCode.php index 6602e5bf..32cb372a 100644 --- a/src/Services/Placement/Service/PlacementLocationCode.php +++ b/src/Services/Placement/Service/PlacementLocationCode.php @@ -10,83 +10,190 @@ 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_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_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 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 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_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_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 @@ -115,31 +222,19 @@ class PlacementLocationCode // this URL receives a message with text and error code and the embedding itself is deleted. public const PAGE_BACKGROUND_WORKER = 'PAGE_BACKGROUND_WORKER'; - /** - * @param int $entityId - * - * @return string - */ + public function getForCrmDynamicListMenu(int $entityId): string { return sprintf('CRM_DYNAMIC_%s_LIST_MENU', $entityId); } - /** - * @param int $entityId - * - * @return string - */ + public function getForCrmDynamicDetailTab(int $entityId): string { return sprintf('CRM_DYNAMIC_%s_DETAIL_TAB', $entityId); } - /** - * @param int $entityId - * - * @return string - */ + public function getForCrmDynamicDetailActivity(int $entityId): string { return sprintf('CRM_DYNAMIC_%s_DETAIL_ACTIVITY', $entityId); diff --git a/src/Services/Placement/Service/UserFieldType.php b/src/Services/Placement/Service/UserFieldType.php index c37c8c2f..f921f39c 100644 --- a/src/Services/Placement/Service/UserFieldType.php +++ b/src/Services/Placement/Service/UserFieldType.php @@ -4,11 +4,16 @@ 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 { /** @@ -19,11 +24,15 @@ class UserFieldType extends AbstractService * @param string $title Type text name. Will be displayed in the admin interface of user field settings. * @param string $description Type text description. Will be displayed in the admin interface of user field settings. * - * @return \Bitrix24\SDK\Services\Placement\Result\RegisterUserTypeResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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( @@ -42,11 +51,15 @@ public function add(string $userTypeId, string $handlerUrl, string $title, strin /** * Retrieves list of user field types, registrered by the application. List method. Results in the list of field types with page-by-page navigation. * - * @return UserFieldTypesResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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( @@ -62,11 +75,15 @@ public function list(): UserFieldTypesResult * @param string $title Type text name. Will be displayed in the admin interface of user field settings. * @param string $description Type text description. Will be displayed in the admin interface of user field settings. * - * @return \Bitrix24\SDK\Services\Placement\Result\RegisterUserTypeResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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( @@ -87,11 +104,15 @@ public function update(string $userTypeId, string $handlerUrl, string $title, st * * @param string $userTypeId Inline code of the type. Required parameter. a-z0-9 * - * @return \Bitrix24\SDK\Services\Placement\Result\DeleteUserTypeResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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( diff --git a/src/Services/Telephony/Call/Service/Call.php b/src/Services/Telephony/Call/Service/Call.php index 4ffa221e..68be1cfc 100644 --- a/src/Services/Telephony/Call/Service/Call.php +++ b/src/Services/Telephony/Call/Service/Call.php @@ -4,7 +4,10 @@ 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; @@ -13,7 +16,7 @@ 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( @@ -34,6 +37,11 @@ public function __construct( * @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, diff --git a/src/Services/Telephony/ExternalCall/Service/ExternalCall.php b/src/Services/Telephony/ExternalCall/Service/ExternalCall.php index 64dedbfe..98cc1180 100644 --- a/src/Services/Telephony/ExternalCall/Service/ExternalCall.php +++ b/src/Services/Telephony/ExternalCall/Service/ExternalCall.php @@ -4,7 +4,10 @@ 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; @@ -24,6 +27,7 @@ use Money\Money; use Psr\Log\LoggerInterface; +#[ApiServiceMetadata(new Scope(['telephony']))] class ExternalCall extends AbstractService { public function __construct( @@ -47,6 +51,11 @@ public function __construct( * @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, @@ -70,6 +79,11 @@ public function getCallRecordUploadUrl( * @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, @@ -125,6 +139,11 @@ public function attachCallRecordInBase64( * @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, @@ -184,6 +203,11 @@ public function register( * @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', @@ -203,6 +227,11 @@ public function searchCrmEntities(string $phoneNumber): SearchCrmEntitiesResult * @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, @@ -239,6 +268,11 @@ public function finishForUserPhoneInner( * @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, @@ -273,6 +307,11 @@ public function finishForUserId( * @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', @@ -291,6 +330,11 @@ public function show(string $callId, array $b24UserId): UserInterfaceDialogCallR * @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', diff --git a/src/Services/Telephony/ExternalLine/Service/ExternalLine.php b/src/Services/Telephony/ExternalLine/Service/ExternalLine.php index 969aaa92..b9169af1 100644 --- a/src/Services/Telephony/ExternalLine/Service/ExternalLine.php +++ b/src/Services/Telephony/ExternalLine/Service/ExternalLine.php @@ -4,16 +4,18 @@ 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 Bitrix24\SDK\Services\Telephony\ExternalLine\Service\Batch; use Psr\Log\LoggerInterface; - +#[ApiServiceMetadata(new Scope(['telephony']))] class ExternalLine extends AbstractService { public function __construct( @@ -36,6 +38,11 @@ public function __construct( * @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', [ @@ -52,6 +59,11 @@ public function add(string $lineNumber, bool $isAutoCreateCrmEntities = true, ?s * @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', [ @@ -66,6 +78,11 @@ public function delete(string $lineNumber): EmptyResult * @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')); diff --git a/src/Services/Telephony/Voximplant/InfoCall/Service/InfoCall.php b/src/Services/Telephony/Voximplant/InfoCall/Service/InfoCall.php index 47cc133b..a88266a9 100644 --- a/src/Services/Telephony/Voximplant/InfoCall/Service/InfoCall.php +++ b/src/Services/Telephony/Voximplant/InfoCall/Service/InfoCall.php @@ -4,14 +4,17 @@ 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( @@ -36,6 +39,11 @@ public function __construct( * @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', [ @@ -46,6 +54,11 @@ public function startWithText(string $lineId, string $toNumber, string $text, ?s ])); } + #[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', [ diff --git a/src/Services/Telephony/Voximplant/Line/Service/Line.php b/src/Services/Telephony/Voximplant/Line/Service/Line.php index 472dd8df..bfc873f8 100644 --- a/src/Services/Telephony/Voximplant/Line/Service/Line.php +++ b/src/Services/Telephony/Voximplant/Line/Service/Line.php @@ -4,7 +4,10 @@ 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; @@ -12,7 +15,7 @@ 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( @@ -30,6 +33,11 @@ public function __construct( * 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', [ @@ -42,6 +50,11 @@ public function outgoingSipSet(int $sipLineId): UserInterfaceDialogCallResult * * @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')); @@ -54,6 +67,11 @@ public function get(): VoximplantLinesResult * * @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')); @@ -68,6 +86,11 @@ public function outgoingGet(): VoximplantLineIdResult * @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', [ diff --git a/src/Services/Telephony/Voximplant/Sip/Service/Sip.php b/src/Services/Telephony/Voximplant/Sip/Service/Sip.php index 09c91902..a310e2c1 100644 --- a/src/Services/Telephony/Voximplant/Sip/Service/Sip.php +++ b/src/Services/Telephony/Voximplant/Sip/Service/Sip.php @@ -4,7 +4,10 @@ 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; @@ -17,7 +20,7 @@ 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( @@ -37,6 +40,11 @@ public function __construct( * @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')); @@ -49,6 +57,11 @@ public function getConnectorStatus(): SipConnectorStatusResult * * @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, @@ -75,6 +88,11 @@ public function add( * @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', [ @@ -90,6 +108,11 @@ public function delete(int $sipConfigId): DeletedItemResult * @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')); @@ -105,6 +128,11 @@ public function get(): SipLinesResult * @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', [ @@ -120,6 +148,11 @@ public function status(int $sipRegistrationId): SipLineStatusResult * @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, diff --git a/src/Services/Telephony/Voximplant/TTS/Voices/Service/Voices.php b/src/Services/Telephony/Voximplant/TTS/Voices/Service/Voices.php index a322299f..b8a000e2 100644 --- a/src/Services/Telephony/Voximplant/TTS/Voices/Service/Voices.php +++ b/src/Services/Telephony/Voximplant/TTS/Voices/Service/Voices.php @@ -4,7 +4,10 @@ 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; @@ -12,6 +15,7 @@ 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( @@ -31,6 +35,11 @@ public function __construct( * @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')); diff --git a/src/Services/Telephony/Voximplant/Url/Service/Url.php b/src/Services/Telephony/Voximplant/Url/Service/Url.php index 1a5e8c06..d738bff6 100644 --- a/src/Services/Telephony/Voximplant/Url/Service/Url.php +++ b/src/Services/Telephony/Voximplant/Url/Service/Url.php @@ -4,13 +4,16 @@ 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( @@ -30,6 +33,11 @@ public function __construct( * @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')); diff --git a/src/Services/Telephony/Voximplant/User/Service/User.php b/src/Services/Telephony/Voximplant/User/Service/User.php index d77bdd1c..cd163b13 100644 --- a/src/Services/Telephony/Voximplant/User/Service/User.php +++ b/src/Services/Telephony/Voximplant/User/Service/User.php @@ -4,25 +4,17 @@ 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\InvalidArgumentException; use Bitrix24\SDK\Core\Exceptions\TransportException; -use Bitrix24\SDK\Core\Result\DeletedItemResult; -use Bitrix24\SDK\Core\Result\EmptyResult; -use Bitrix24\SDK\Core\Result\UpdatedItemResult; use Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult; use Bitrix24\SDK\Services\AbstractService; -use Bitrix24\SDK\Services\Telephony\Common\PbxType; -use Bitrix24\SDK\Services\Telephony\ExternalLine\Result\ExternalLineAddedResult; -use Bitrix24\SDK\Services\Telephony\ExternalLine\Result\ExternalLinesResult; -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\SipLineStatusItemResult; -use Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result\SipLineStatusResult; use Bitrix24\SDK\Services\Telephony\Voximplant\User\Result\VoximplantUserSettingsResult; use Psr\Log\LoggerInterface; - +#[ApiServiceMetadata(new Scope(['telephony']))] class User extends AbstractService { public function __construct( @@ -43,6 +35,11 @@ public function __construct( * @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', [ @@ -59,6 +56,11 @@ public function deactivatePhone(int $userId): UserInterfaceDialogCallResult * @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', [ @@ -76,6 +78,11 @@ public function activatePhone(int $userId): UserInterfaceDialogCallResult * @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', diff --git a/src/Services/User/Service/User.php b/src/Services/User/Service/User.php index 1590a7db..18ba6426 100644 --- a/src/Services/User/Service/User.php +++ b/src/Services/User/Service/User.php @@ -4,6 +4,9 @@ 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; @@ -14,6 +17,7 @@ use Bitrix24\SDK\Services\User\Result\UserResult; use Bitrix24\SDK\Services\User\Result\UsersResult; +#[ApiServiceMetadata(new Scope(['user']))] class User extends AbstractService { /** @@ -22,6 +26,11 @@ class User extends AbstractService * @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')); @@ -33,6 +42,11 @@ public function fields(): FieldsResult * @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')); @@ -46,6 +60,11 @@ public function current(): UserResult * @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)) { @@ -68,6 +87,11 @@ public function add(array $fields, string $messageText = ''): AddedItemResult * @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 === []) { @@ -88,6 +112,11 @@ public function get(array $order, array $filter, bool $isAdminMode = false): Use * @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( @@ -105,6 +134,11 @@ public function update(int $userId, array $fields): UpdatedItemResult * @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)); diff --git a/src/Services/UserConsent/Result/UserConsentAgreementResult.php b/src/Services/UserConsent/Result/UserConsentAgreementResult.php index 9738998c..3b9cd274 100644 --- a/src/Services/UserConsent/Result/UserConsentAgreementResult.php +++ b/src/Services/UserConsent/Result/UserConsentAgreementResult.php @@ -5,13 +5,13 @@ namespace Bitrix24\SDK\Services\UserConsent\Result; +use Bitrix24\SDK\Core\Exceptions\BaseException; use Bitrix24\SDK\Core\Result\AbstractResult; class UserConsentAgreementResult extends AbstractResult { /** - * @return \Bitrix24\SDK\Services\UserConsent\Result\UserConsentAgreementItemResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @throws BaseException */ public function agreement(): UserConsentAgreementItemResult { diff --git a/src/Services/UserConsent/Result/UserConsentAgreementTextResult.php b/src/Services/UserConsent/Result/UserConsentAgreementTextResult.php index 591c16d5..713c779b 100644 --- a/src/Services/UserConsent/Result/UserConsentAgreementTextResult.php +++ b/src/Services/UserConsent/Result/UserConsentAgreementTextResult.php @@ -10,7 +10,6 @@ class UserConsentAgreementTextResult extends AbstractResult { /** - * @return \Bitrix24\SDK\Services\UserConsent\Result\UserConsentAgreementTextItemResult * @throws \Bitrix24\SDK\Core\Exceptions\BaseException */ public function text(): UserConsentAgreementTextItemResult diff --git a/src/Services/UserConsent/Service/UserConsent.php b/src/Services/UserConsent/Service/UserConsent.php index 05fc9896..02a3a6f8 100644 --- a/src/Services/UserConsent/Service/UserConsent.php +++ b/src/Services/UserConsent/Service/UserConsent.php @@ -4,9 +4,14 @@ 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 { /** @@ -14,12 +19,15 @@ class UserConsent extends AbstractService * * @see https://training.bitrix24.com/rest_help/userconsent/userconsent_consent_add.php * - * @param array $consentFields * - * @return AddedItemResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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)); diff --git a/src/Services/UserConsent/Service/UserConsentAgreement.php b/src/Services/UserConsent/Service/UserConsentAgreement.php index d5418d19..988764e9 100644 --- a/src/Services/UserConsent/Service/UserConsentAgreement.php +++ b/src/Services/UserConsent/Service/UserConsentAgreement.php @@ -4,35 +4,50 @@ 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 * - * @return \Bitrix24\SDK\Services\UserConsent\Result\UserConsentAgreementsResult - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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 \Bitrix24\SDK\Core\Exceptions\TransportException - * @throws \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException + * @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'); } diff --git a/src/Services/UserConsent/UserConsentServiceBuilder.php b/src/Services/UserConsent/UserConsentServiceBuilder.php index 509966d0..e1acfaf0 100644 --- a/src/Services/UserConsent/UserConsentServiceBuilder.php +++ b/src/Services/UserConsent/UserConsentServiceBuilder.php @@ -12,8 +12,6 @@ class UserConsentServiceBuilder extends AbstractServiceBuilder { /** * get user consent agreement service - * - * @return UserConsentAgreement */ public function UserConsentAgreement(): UserConsentAgreement { @@ -26,8 +24,6 @@ public function UserConsentAgreement(): UserConsentAgreement /** * get user consent service - * - * @return UserConsent */ public function UserConsent(): UserConsent { diff --git a/src/Services/Workflows/Activity/Service/Activity.php b/src/Services/Workflows/Activity/Service/Activity.php index 6de4f601..4360fea1 100644 --- a/src/Services/Workflows/Activity/Service/Activity.php +++ b/src/Services/Workflows/Activity/Service/Activity.php @@ -4,7 +4,10 @@ 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; @@ -16,7 +19,7 @@ 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( @@ -35,6 +38,11 @@ public function __construct( * @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', [ @@ -50,6 +58,11 @@ public function log(string $eventToken, string $message): Workflows\Activity\Res * @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')); @@ -75,6 +88,11 @@ public function list(): Workflows\Activity\Result\WorkflowActivitiesResult * @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, @@ -112,6 +130,11 @@ public function add( * @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( @@ -140,6 +163,11 @@ public function delete(string $activityCode): DeletedItemResult * @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, diff --git a/src/Services/Workflows/Event/Service/Event.php b/src/Services/Workflows/Event/Service/Event.php index a36958b3..5596625b 100644 --- a/src/Services/Workflows/Event/Service/Event.php +++ b/src/Services/Workflows/Event/Service/Event.php @@ -4,13 +4,16 @@ 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( @@ -30,6 +33,11 @@ public function __construct( * @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, diff --git a/src/Services/Workflows/Robot/Service/Robot.php b/src/Services/Workflows/Robot/Service/Robot.php index c77e7dd8..891f5ce7 100644 --- a/src/Services/Workflows/Robot/Service/Robot.php +++ b/src/Services/Workflows/Robot/Service/Robot.php @@ -4,7 +4,10 @@ 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; @@ -16,7 +19,7 @@ use Bitrix24\SDK\Services\Workflows\Template\Service\Batch; use Psr\Log\LoggerInterface; - +#[ApiServiceMetadata(new Scope(['bizproc']))] class Robot extends AbstractService { public function __construct( @@ -37,6 +40,11 @@ public function __construct( * @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, @@ -67,6 +75,11 @@ public function add( * @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')); @@ -80,6 +93,11 @@ public function list(): Workflows\Robot\Result\WorkflowRobotsResult * @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( @@ -98,6 +116,11 @@ public function delete(string $robotCode): DeletedItemResult * @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, diff --git a/src/Services/Workflows/Task/Service/Task.php b/src/Services/Workflows/Task/Service/Task.php index 7d209803..ca5ee0a8 100644 --- a/src/Services/Workflows/Task/Service/Task.php +++ b/src/Services/Workflows/Task/Service/Task.php @@ -4,7 +4,10 @@ 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; @@ -17,7 +20,7 @@ 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( @@ -43,6 +46,11 @@ public function __construct( * @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', [ @@ -108,6 +116,11 @@ public function complete(int $taskId, WorkflowTaskCompleteStatusType $status, st * @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 = [], diff --git a/src/Services/Workflows/Template/Service/Template.php b/src/Services/Workflows/Template/Service/Template.php index 2d62f485..44874a13 100644 --- a/src/Services/Workflows/Template/Service/Template.php +++ b/src/Services/Workflows/Template/Service/Template.php @@ -4,7 +4,10 @@ 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; @@ -16,7 +19,7 @@ use Bitrix24\SDK\Services\Workflows; use Psr\Log\LoggerInterface; - +#[ApiServiceMetadata(new Scope(['bizproc']))] class Template extends AbstractService { public function __construct( @@ -37,6 +40,11 @@ public function __construct( * @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, @@ -67,6 +75,11 @@ public function add( * @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, @@ -115,6 +128,11 @@ public function update( * @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', [ @@ -129,6 +147,11 @@ public function delete(int $templateId): DeletedItemResult * @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 diff --git a/src/Services/Workflows/Workflow/Service/Workflow.php b/src/Services/Workflows/Workflow/Service/Workflow.php index 78e38c06..7d938525 100644 --- a/src/Services/Workflows/Workflow/Service/Workflow.php +++ b/src/Services/Workflows/Workflow/Service/Workflow.php @@ -4,14 +4,17 @@ 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( @@ -32,6 +35,11 @@ public function __construct( * @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', [ @@ -45,6 +53,11 @@ public function kill(string $workflowId): Workflows\Workflow\Result\WorkflowKill * @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', [ @@ -62,6 +75,11 @@ public function terminate(string $workflowId, string $message): Workflows\Workfl * @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, @@ -124,6 +142,11 @@ public function start( * @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'], diff --git a/tests/.env b/tests/.env index 6fc806a2..dc897384 100644 --- a/tests/.env +++ b/tests/.env @@ -20,4 +20,6 @@ BITRIX24_WEBHOOK= # monolog log level INTEGRATION_TEST_LOG_LEVEL=200 # integration tests assets -INTEGRATION_TEST_OPEN_LINE_CODE=40863c519996e505b5cde98749c97413 \ No newline at end of file +INTEGRATION_TEST_OPEN_LINE_CODE=40863c519996e505b5cde98749c97413 + +DOCUMENTATION_DEFAULT_TARGET_BRANCH= \ 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 index dc106b5b..c20dafc9 100644 --- a/tests/Integration/Services/Catalog/Catalog/Service/CatalogTest.php +++ b/tests/Integration/Services/Catalog/Catalog/Service/CatalogTest.php @@ -8,54 +8,47 @@ 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; /** - * Test the Fields method. - * - * @return void * @throws BaseException if there is a base exception occurred * @throws TransportException if there is a transport exception occurred - * @covers \Bitrix24\SDK\Services\Catalog\Catalog\Service\Catalog::fields - * @testdox Test Catalog::fields method */ + #[TestDox('Test Catalog::fields method')] public function testFields(): void { $this->assertIsArray($this->service->fields()->getFieldsDescription()); } /** - * Test the List method. - * - * @return void * @throws BaseException if there is a base exception occurred * @throws TransportException if there is a transport exception occurred - * @covers \Bitrix24\SDK\Services\Catalog\Catalog\Service\Catalog::list */ + #[TestDox('Test Catalog::list method')] public function testList(): void { $this->assertGreaterThan(1, $this->service->list([], [], [], 1)->getCatalogs()[0]->id); } /** - * Retrieves a catalog using the `get` method and asserts that the retrieved catalog's ID matches the original catalog's ID. - * - * @return void * @throws BaseException if there is a general exception. * @throws TransportException if there is an exception during transport. - * @covers \Bitrix24\SDK\Services\Catalog\Catalog\Service\Catalog::get */ + #[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); } - public function setUp(): void + protected function setUp(): void { $this->service = Fabric::getServiceBuilder()->getCatalogScope()->catalog(); } diff --git a/tests/Integration/Services/Catalog/Product/Service/ProductTest.php b/tests/Integration/Services/Catalog/Product/Service/ProductTest.php index 5628390e..08501130 100644 --- a/tests/Integration/Services/Catalog/Product/Service/ProductTest.php +++ b/tests/Integration/Services/Catalog/Product/Service/ProductTest.php @@ -10,23 +10,22 @@ 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; /** - * Tests the fieldsByFilter method. - * - * @return void - * * @throws BaseException * @throws TransportException - * @covers \Bitrix24\SDK\Services\Catalog\Product\Service\Product::fieldsByFilter - * @testdox test Product::fieldsByFilter */ + #[TestDox('test Product::fieldsByFilter')] public function testFieldsByFilter(): void { $iblockId = $this->catalogService->list([], [], [], 1)->getCatalogs()[0]->iblockId; @@ -37,13 +36,10 @@ public function testFieldsByFilter(): void } /** - * Adds a new product to the system and asserts that the product was added successfully. - * - * @return void * @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. - * @covers Product::add() */ + #[TestDox('test Product::add')] public function testAdd(): void { $iblockId = $this->catalogService->list([], [], [], 1)->getCatalogs()[0]->iblockId; @@ -52,19 +48,16 @@ public function testAdd(): void 'name' => sprintf('test product name %s', time()), '' ]; - $result = $this->productService->add($fields); - $this->assertEquals($fields['name'], $result->product()->name); - $this->productService->delete($result->product()->id); + $productResult = $this->productService->add($fields); + $this->assertEquals($fields['name'], $productResult->product()->name); + $this->productService->delete($productResult->product()->id); } /** - * Retrieves a product from the system and asserts that the correct product was retrieved. - * - * @return void * @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. - * @covers Product::get() */ + #[TestDox('test Product::get')] public function testGet(): void { $iblockId = $this->catalogService->list([], [], [], 1)->getCatalogs()[0]->iblockId; @@ -72,21 +65,19 @@ public function testGet(): void 'iblockId' => $iblockId, 'name' => sprintf('test product name %s', time()), ]; - $result = $this->productService->add($fields); - $productGet = $this->productService->get($result->product()->id); - $this->assertEquals($result->product()->id, $productGet->product()->id); + $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. * - * @return void * @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. - * @covers Product::delete() - * @testdox test Product::delete */ + #[TestDox('test Product::delete')] public function testDelete(): void { $iblockId = $this->catalogService->list([], [], [], 1)->getCatalogs()[0]->iblockId; @@ -94,12 +85,12 @@ public function testDelete(): void 'iblockId' => $iblockId, 'name' => sprintf('test product name %s', time()), ]; - $result = $this->productService->add($fields); - $productGet = $this->productService->get($result->product()->id); - $this->assertEquals($result->product()->id, $productGet->product()->id); + $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); - $filteredProducts = $this->productService->list( + $productsResult = $this->productService->list( [ 'id', 'iblockId' @@ -113,17 +104,16 @@ public function testDelete(): void ], 1 ); - $this->assertCount(0, $filteredProducts->getProducts()); + $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. * - * @return void * @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. - * @covers Product::list() */ + #[TestDox('test Product::list')] public function testList():void { $iblockId = $this->catalogService->list([], [], [], 1)->getCatalogs()[0]->iblockId; @@ -131,10 +121,10 @@ public function testList():void 'iblockId' => $iblockId, 'name' => sprintf('test product name %s', time()), ]; - $result = $this->productService->add($fields); - $productGet = $this->productService->get($result->product()->id); - $this->assertEquals($result->product()->id, $productGet->product()->id); - $filteredProducts = $this->productService->list( + $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' @@ -148,10 +138,10 @@ public function testList():void ], 1 ); - $this->assertCount(1, $filteredProducts->getProducts()); + $this->assertCount(1, $productsResult->getProducts()); } - public function setUp(): void + protected function setUp(): void { $this->productService = Fabric::getServiceBuilder()->getCatalogScope()->product(); $this->catalogService = Fabric::getServiceBuilder()->getCatalogScope()->catalog(); diff --git a/tests/Integration/Services/IM/Service/NotifyTest.php b/tests/Integration/Services/IM/Service/NotifyTest.php new file mode 100644 index 00000000..976c0162 --- /dev/null +++ b/tests/Integration/Services/IM/Service/NotifyTest.php @@ -0,0 +1,160 @@ +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 index 80948a9e..ee1f2e9a 100644 --- a/tests/Integration/Services/IMOpenLines/Service/NetworkTest.php +++ b/tests/Integration/Services/IMOpenLines/Service/NetworkTest.php @@ -4,46 +4,47 @@ 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; /** - * @covers \Bitrix24\SDK\Services\IMOpenLines\Service\Network::join - * @testdox test get agreements list - * @return void - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws BaseException + * @throws TransportException */ + #[TestDox('test get agreements list')] public function testJoin(): void { - $res = $this->networkService->join(Fabric::getOpenLineCode()); - $this->assertGreaterThanOrEqual(1, $res->getId()); + $joinOpenLineResult = $this->networkService->join(Fabric::getOpenLineCode()); + $this->assertGreaterThanOrEqual(1, $joinOpenLineResult->getId()); } /** - * @covers \Bitrix24\SDK\Services\IMOpenLines\Service\Network::join - * @testdox test get agreements list - * @return void - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws BaseException + * @throws TransportException */ + #[TestDox('test get agreements list')] public function testMessageAdd(): void { - $res = $this->networkService->messageAdd( + $addedMessageItemResult = $this->networkService->messageAdd( Fabric::getOpenLineCode(), (int)$this->networkService->core->call('PROFILE')->getResponseData()->getResult()['ID'], sprintf('Test message at %s', time()) ); - $this->assertTrue($res->isSuccess()); + $this->assertTrue($addedMessageItemResult->isSuccess()); } - public function setUp(): void + protected function setUp(): void { $this->networkService = Fabric::getServiceBuilder()->getIMOpenLinesScope()->Network(); } diff --git a/tests/Integration/Services/Main/Service/MainTest.php b/tests/Integration/Services/Main/Service/MainTest.php index d4bd3adc..7fab4e12 100644 --- a/tests/Integration/Services/Main/Service/MainTest.php +++ b/tests/Integration/Services/Main/Service/MainTest.php @@ -5,19 +5,23 @@ 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; /** - * @covers \Bitrix24\SDK\Services\Main\Service\Main::getServerTime - * @return void - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws BaseException + * @throws TransportException */ public function testGetServerTime(): void { @@ -26,22 +30,18 @@ public function testGetServerTime(): void } /** - * @covers \Bitrix24\SDK\Services\Main\Service\Main::getCurrentUserProfile - * @return void - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws BaseException + * @throws TransportException */ public function testGetCurrentUserProfile(): void { - $profile = $this->mainService->getCurrentUserProfile()->getUserProfile(); - $this->assertTrue($profile->ADMIN); + $userProfileItemResult = $this->mainService->getCurrentUserProfile()->getUserProfile(); + $this->assertTrue($userProfileItemResult->ADMIN); } /** - * @covers \Bitrix24\SDK\Services\Main\Service\Main::isCurrentUserHasAdminRights - * @return void - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws BaseException + * @throws TransportException */ public function testIsUserIsAdmin(): void { @@ -49,10 +49,8 @@ public function testIsUserIsAdmin(): void } /** - * @covers \Bitrix24\SDK\Services\Main\Service\Main::getMethodAffordability - * @return void - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws BaseException + * @throws TransportException */ public function testMethodGetInformationForNonExistsMethod(): void { @@ -61,10 +59,8 @@ public function testMethodGetInformationForNonExistsMethod(): void } /** - * @covers \Bitrix24\SDK\Services\Main\Service\Main::getApplicationInfo - * @return void - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws BaseException + * @throws TransportException */ public function testApplicationInfo(): void { @@ -72,10 +68,9 @@ public function testApplicationInfo(): void } /** - * @return void - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException - * @throws \Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException + * @throws BaseException + * @throws TransportException + * @throws UnknownScopeCodeException */ public function testGetAvailableScope(): void { @@ -84,10 +79,9 @@ public function testGetAvailableScope(): void } /** - * @return void - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException - * @throws \Bitrix24\SDK\Core\Exceptions\UnknownScopeCodeException + * @throws BaseException + * @throws TransportException + * @throws UnknownScopeCodeException */ public function testGetCurrentScope(): void { @@ -98,18 +92,16 @@ public function testGetCurrentScope(): void } /** - * @covers \Bitrix24\SDK\Services\Main\Service\Main::getAvailableMethods - * @testdox test methods list - * @return void - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws BaseException + * @throws TransportException */ + #[TestDox('test methods list')] public function testGetAvailableMethods(): void { $this->assertIsArray($this->mainService->getAvailableMethods()->getResponseData()->getResult()); } - public function setUp(): void + protected function setUp(): void { $this->mainService = Fabric::getServiceBuilder()->getMainScope()->main(); } diff --git a/tests/Integration/Services/Placement/Service/PlacementTest.php b/tests/Integration/Services/Placement/Service/PlacementTest.php new file mode 100644 index 00000000..1084efcc --- /dev/null +++ b/tests/Integration/Services/Placement/Service/PlacementTest.php @@ -0,0 +1,103 @@ +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/UserConsent/Service/UserConsentAgreementTest.php b/tests/Integration/Services/UserConsent/Service/UserConsentAgreementTest.php index 3f694869..76e8ff54 100644 --- a/tests/Integration/Services/UserConsent/Service/UserConsentAgreementTest.php +++ b/tests/Integration/Services/UserConsent/Service/UserConsentAgreementTest.php @@ -4,8 +4,11 @@ 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 @@ -13,45 +16,42 @@ class UserConsentAgreementTest extends TestCase private UserConsentAgreement $userConsentAgreementService; /** - * @covers UserConsentAgreement::list - * @testdox test get agreements list - * @return void - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @throws BaseException + * @throws TransportException */ + #[TestDox('test get agreements list')] public function testList(): void { $this->assertIsArray($this->userConsentAgreementService->list()->getAgreements()); } /** - * @covers UserConsentAgreement::text - * @testdox test get agreements list - * @return void - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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 (count($agreements) === 0) { + if ($agreements === []) { $this->assertTrue(true); return; } + $agreementId = $agreements[0]->ID; - $agreementText = $this->userConsentAgreementService->text($agreementId, [ + $userConsentAgreementTextItemResult = $this->userConsentAgreementService->text($agreementId, [ 'button_caption' => 'Button call to action title', 'fields' => 'fields collection: email, phone', ])->text(); - $this->assertNotNull($agreementText->TEXT); - $this->assertNotNull($agreementText->LABEL); + $this->assertNotNull($userConsentAgreementTextItemResult->TEXT); + $this->assertNotNull($userConsentAgreementTextItemResult->LABEL); } - public function setUp(): void + protected function setUp(): void { $this->userConsentAgreementService = Fabric::getServiceBuilder()->getUserConsentScope()->UserConsentAgreement(); } diff --git a/tests/Integration/Services/UserConsent/Service/UserConsentTest.php b/tests/Integration/Services/UserConsent/Service/UserConsentTest.php index 7759a6a2..7f2c25c8 100644 --- a/tests/Integration/Services/UserConsent/Service/UserConsentTest.php +++ b/tests/Integration/Services/UserConsent/Service/UserConsentTest.php @@ -4,36 +4,38 @@ 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; /** - * @covers UserConsent::add - * @testdox test get agreements list - * @return void - * @throws \Bitrix24\SDK\Core\Exceptions\BaseException - * @throws \Bitrix24\SDK\Core\Exceptions\TransportException + * @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 (count($agreements) === 0) { + if ($agreements === []) { $this->assertTrue(true); return; } $agreementId = $agreements[0]->ID; - $res = $this->userConsentService->add( + $addedItemResult = $this->userConsentService->add( [ 'agreement_id' => $agreementId, 'ip' => '127.0.0.1', @@ -41,10 +43,10 @@ public function testAdd(): void 'originator_id' => 'test@gmail.com', ] ); - $this->assertIsInt($res->getId()); + $this->assertIsInt($addedItemResult->getId()); } - public function setUp(): void + protected function setUp(): void { $this->userConsentService = Fabric::getServiceBuilder()->getUserConsentScope()->UserConsent(); $this->userConsentAgreementService = Fabric::getServiceBuilder()->getUserConsentScope()->UserConsentAgreement(); diff --git a/tests/Unit/Services/IM/IMServiceBuilderTest.php b/tests/Unit/Services/IM/IMServiceBuilderTest.php index 27b5bc8a..d151d96a 100644 --- a/tests/Unit/Services/IM/IMServiceBuilderTest.php +++ b/tests/Unit/Services/IM/IMServiceBuilderTest.php @@ -9,22 +9,18 @@ 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; -/** - * Class IMServiceBuilderTest - * - * @package Bitrix24\SDK\Tests\Unit\Services\IM - */ -#[\PHPUnit\Framework\Attributes\CoversClass(\Bitrix24\SDK\Services\IM\IMServiceBuilder::class)] +#[CoversClass(IMServiceBuilder::class)] class IMServiceBuilderTest extends TestCase { private IMServiceBuilder $serviceBuilder; public function testGetIMService(): void { - $this->serviceBuilder->IM(); + $this->serviceBuilder->notify(); $this::assertTrue(true); } From 26994963d80b746b2bd5da1e1f439e95bce218b1 Mon Sep 17 00:00:00 2001 From: mesilov Date: Mon, 26 Aug 2024 01:20:40 +0600 Subject: [PATCH 130/138] Remove outdated examples directory This commit deletes legacy example files and directories that are no longer needed. The removed files include outdated webhook, telephony, and workflow examples that had hardcoded values and were not aligned with the current project architecture. Signed-off-by: mesilov --- README.md | 28 ++- examples/LoggerFactory.php | 22 --- examples/application/local/bp-82.bpt | Bin 5819 -> 0 bytes examples/core/webhook/.env | 5 - examples/core/webhook/composer.json | 21 --- examples/core/webhook/example.php | 30 ---- examples/services/telephony/.env | 9 - .../services/telephony/events-handler.php | 122 -------------- examples/services/telephony/index.php | 63 ------- examples/services/telephony/install.php | 4 - examples/services/workflows/.env | 5 - examples/services/workflows/task.php | 131 --------------- examples/services/workflows/workflow.php | 159 ------------------ examples/webhook/.env | 5 - examples/webhook/composer.json | 6 +- examples/webhook/example.php | 26 ++- 16 files changed, 36 insertions(+), 600 deletions(-) delete mode 100644 examples/LoggerFactory.php delete mode 100644 examples/application/local/bp-82.bpt delete mode 100644 examples/core/webhook/.env delete mode 100644 examples/core/webhook/composer.json delete mode 100644 examples/core/webhook/example.php delete mode 100644 examples/services/telephony/.env delete mode 100644 examples/services/telephony/events-handler.php delete mode 100644 examples/services/telephony/index.php delete mode 100644 examples/services/telephony/install.php delete mode 100644 examples/services/workflows/.env delete mode 100644 examples/services/workflows/task.php delete mode 100644 examples/services/workflows/workflow.php delete mode 100644 examples/webhook/.env diff --git a/README.md b/README.md index 9e7120ca..bbe60abe 100644 --- a/README.md +++ b/README.md @@ -99,27 +99,43 @@ Add `"mesilov/bitrix24-php-sdk": "2.x"` to `composer.json` of your application. ## Examples ### Work with webhook - +1. Go to `/examples/webhook` folder +2. Open console and install dependencies +```shell +composer install +``` +3. Open example file and insert webhook url into `$webhookUrl` ```php declare(strict_types=1); use Bitrix24\SDK\Services\ServiceBuilderFactory; -use Monolog\Logger; use Symfony\Component\EventDispatcher\EventDispatcher; +use Monolog\Logger; +use Monolog\Handler\StreamHandler; +use Monolog\Processor\MemoryUsageProcessor; -require_once 'vendor/autoload.php'; +require_once 'vendor/autoload.php'; $webhookUrl = 'INSERT_HERE_YOUR_WEBHOOK_URL'; $log = new Logger('bitrix24-php-sdk'); -$b24ServiceFactory = new ServiceBuilderFactory(new EventDispatcher(), $log); +$log->pushHandler(new StreamHandler('bitrix24-php-sdk.log')); +$log->pushProcessor(new MemoryUsageProcessor(true, true)); -// init bitrix24-php-sdk service +// 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()); -var_dump($b24Service->getCRMScope()->lead()->list([],[],['ID','TITLE'])->getLeads()[0]->TITLE); +// get deals list and address to first element +var_dump($b24Service->getCRMScope()->lead()->list([], [], ['ID', 'TITLE'])->getLeads()[0]->TITLE); +``` +4. call php file in cli +```shell +php -f example.php + ``` ### Create application for Bitrix24 marketplace diff --git a/examples/LoggerFactory.php b/examples/LoggerFactory.php deleted file mode 100644 index bb18fcdb..00000000 --- a/examples/LoggerFactory.php +++ /dev/null @@ -1,22 +0,0 @@ -pushHandler(new StreamHandler($_ENV['LOGS_FILE_NAME'], (int)$_ENV['LOGS_LEVEL'])); - $log->pushProcessor(new MemoryUsageProcessor(true, true)); - $log->pushProcessor(new IntrospectionProcessor((int)$_ENV['LOGS_LEVEL'])); - - return $log; - } -} \ No newline at end of file diff --git a/examples/application/local/bp-82.bpt b/examples/application/local/bp-82.bpt deleted file mode 100644 index 227b054cf989a7531b029c042fe24f5ab2390209..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5819 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 FgH402c^?1( diff --git a/examples/core/webhook/.env b/examples/core/webhook/.env deleted file mode 100644 index 1355fb8e..00000000 --- a/examples/core/webhook/.env +++ /dev/null @@ -1,5 +0,0 @@ -# bitrix24 webhook url -BITRIX24_WEBHOOK_URL= -# monolog -LOG_LEVEL=100 -LOG_FILE_NAME=bitrix24-php-sdk.log diff --git a/examples/core/webhook/composer.json b/examples/core/webhook/composer.json deleted file mode 100644 index 11c0dc0c..00000000 --- a/examples/core/webhook/composer.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "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-371-publish-b24-php-sdk-beta-2", - "monolog/monolog": "3.5.*", - "symfony/dotenv": "7.0.*", - - }, - "require-dev": { - "roave/security-advisories": "dev-latest" - } -} \ No newline at end of file diff --git a/examples/core/webhook/example.php b/examples/core/webhook/example.php deleted file mode 100644 index 03e40fd2..00000000 --- a/examples/core/webhook/example.php +++ /dev/null @@ -1,30 +0,0 @@ -loadEnv('.env'); -$webhookUrl = $_ENV['BITRIX24_WEBHOOK_URL']; - -// configure logger for debug queries -$log = new Logger('bitrix24-php-sdk'); -$log->pushHandler(new StreamHandler($_ENV['LOG_FILE_NAME'], (int)$_ENV['LOG_LEVEL'])); -$log->pushProcessor(new MemoryUsageProcessor(true, true)); -$log->pushProcessor(new IntrospectionProcessor()); - -// create factory for build service from multiple sources: webhook, request, bitrix24 account with oauth2.0 tokens -$b24ServiceFactory = new ServiceBuilderFactory(new EventDispatcher(), $log); -// init bitrix24-php-sdk service with webhook credentials -$b24Service = $b24ServiceFactory->initFromWebhook($webhookUrl); - -$deal = $b24Service->getCRMScope()->deal()->get(1)->deal(); -var_dump($deal->TITLE); \ No newline at end of file diff --git a/examples/services/telephony/.env b/examples/services/telephony/.env deleted file mode 100644 index a15fc445..00000000 --- a/examples/services/telephony/.env +++ /dev/null @@ -1,9 +0,0 @@ -# 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/examples/services/telephony/events-handler.php b/examples/services/telephony/events-handler.php deleted file mode 100644 index cfd23535..00000000 --- a/examples/services/telephony/events-handler.php +++ /dev/null @@ -1,122 +0,0 @@ -bootEnv('.env'); - -if ($_SERVER['APP_DEBUG']) { - umask(0000); - - if (class_exists( - Debug::class - )) { - Debug::enable(); - } -} - -try { - - $log = LoggerFactory::get(); - - $request = Request::createFromGlobals(); - $log->debug('incoming request', [ - 'payload' => $request->request->all() - ]); - - // create telephony event - $event = (new TelephonyEventsFabric())->create($request); - if ($event === null) { - throw new \Bitrix24\SDK\Core\Exceptions\InvalidArgumentException('unknown event code'); - } - $log->debug('received event', [ - 'code' => $event->getEventCode(), - 'payload' => $event->getEventPayload(), - ]); - - // init service builder with auth token from event - $serviceBuilder = (new ServiceBuilderFactory(new EventDispatcher(), $log))->initFromRequest( - ApplicationProfile::initFromArray($_ENV), - AuthToken::initFromEventRequest($request), - $event->getAuth()->client_endpoint - ); - - $curUser = $serviceBuilder->getMainScope()->main()->getCurrentUserProfile()->getUserProfile(); - $log->debug('current user profile', [ - 'id' => $curUser->ID - ]); - $currentB24UserId = $serviceBuilder->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()->ID; - $innerPhoneNumber = '123'; - // set inner phone number for user - $serviceBuilder->getUserScope()->user()->update( - $currentB24UserId, - [ - 'UF_PHONE_INNER' => $innerPhoneNumber - ] - ); - - if ($event instanceof Bitrix24\SDK\Services\Telephony\Events\OnExternalCallBackStart\OnExternalCallBackStart) { - // start call - $phoneNumber = '7978' . random_int(1000000, 9999999); - $b24CallId = $serviceBuilder->getTelephonyScope()->externalCall()->register( - $innerPhoneNumber, - $currentB24UserId, - $phoneNumber, - CarbonImmutable::now(), - CallType::outbound, - true, - true, - '3333', - null, - CrmEntityType::contact - )->getExternalCallRegistered()->CALL_ID; - - //emulate work with external pbx and make real call - sleep(3); - - // finish call - $money = new Money(10000, new Currency('USD')); - $duration = 100; - $finishResult = $serviceBuilder->getTelephonyScope()->externalCall()->finishForUserId( - $b24CallId, - $currentB24UserId, - $duration, - $money, - TelephonyCallStatusCode::successful, - true - ); - } - if ($event instanceof Bitrix24\SDK\Services\Telephony\Events\OnVoximplantCallEnd\OnVoximplantCallEnd) { - $log->debug('OnVoximplantCallEnd event payload', [ - 'paylload' => $event->getEventPayload() - ]); - } -} catch (Throwable $exception) { - - $log->error(sprintf('error: %s', $exception->getMessage()), [ - 'trace' => $exception->getTraceAsString() - ]); - - -} - - diff --git a/examples/services/telephony/index.php b/examples/services/telephony/index.php deleted file mode 100644 index e26e5007..00000000 --- a/examples/services/telephony/index.php +++ /dev/null @@ -1,63 +0,0 @@ - -
-bootEnv('.env'); - -if ($_SERVER['APP_DEBUG']) { - umask(0000); - if (class_exists( - Debug::class - )) { - Debug::enable(); - } -} - -$request = Request::createFromGlobals(); - -$log = LoggerFactory::get(); - -$b24ServiceFactory = new ServiceBuilderFactory(new EventDispatcher(), $log); -$appProfile = ApplicationProfile::initFromArray($_ENV); -$accessToken = AuthToken::initFromPlacementRequest($request); -$b24Service = $b24ServiceFactory->initFromRequest($appProfile, $accessToken, $_REQUEST['DOMAIN']); - - -// subscribe to all events -$handlerUrl = 'https://' . $request->getHost() . '/events-handler.php'; -$b24UserId = $b24Service->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()->ID; -$eventHandlers = [ - new EventHandlerMetadata(OnExternalCallBackStart::CODE, $handlerUrl, $b24UserId), - new EventHandlerMetadata(OnExternalCallStart::CODE, $handlerUrl, $b24UserId), - new EventHandlerMetadata(OnVoximplantCallInit::CODE, $handlerUrl, $b24UserId), - new EventHandlerMetadata(OnVoximplantCallEnd::CODE, $handlerUrl, $b24UserId), - new EventHandlerMetadata(OnVoximplantCallStart::CODE, $handlerUrl, $b24UserId) -]; - - -$b24Service->getMainScope()->eventManager()->bindEventHandlers($eventHandlers); diff --git a/examples/services/telephony/install.php b/examples/services/telephony/install.php deleted file mode 100644 index eae01705..00000000 --- a/examples/services/telephony/install.php +++ /dev/null @@ -1,4 +0,0 @@ - - - \ No newline at end of file diff --git a/examples/services/workflows/.env b/examples/services/workflows/.env deleted file mode 100644 index 24a48adf..00000000 --- a/examples/services/workflows/.env +++ /dev/null @@ -1,5 +0,0 @@ -# bitrix24 webhook url -BITRIX24_WEBHOOK= -# monolog -LOGS_LEVEL=100 -LOGS_FILE_NAME=bitrix24-php-sdk.log \ No newline at end of file diff --git a/examples/services/workflows/task.php b/examples/services/workflows/task.php deleted file mode 100644 index 7f476f6d..00000000 --- a/examples/services/workflows/task.php +++ /dev/null @@ -1,131 +0,0 @@ -#!/usr/bin/env php -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('.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_NAME'], (int)$_ENV['LOGS_LEVEL'])); -$log->pushProcessor(new MemoryUsageProcessor(true, true)); - -$webhookUrl = $_ENV['BITRIX24_WEBHOOK']; -$b24ServiceFactory = new ServiceBuilderFactory(new EventDispatcher(), $log); -// init bitrix24-php-sdk service with webhook credentials -$b24Service = $b24ServiceFactory->initFromWebhook($webhookUrl); - -#[AsCommand( - name: 'bitrix24-php-sdk:examples:workflows:task', - hidden: false -)] -class task extends Command -{ - private LoggerInterface $log; - private ServiceBuilder $serviceBuilder; - - public function __construct(ServiceBuilder $serviceBuilder, 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->log = $logger; - $this->serviceBuilder = $serviceBuilder; - parent::__construct(); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - $output->writeln([ - 'Work with workflow task example', - ]); - - - var_dump($this->serviceBuilder->getBizProcScope()->task()->list( - [], - [], - [ - 'ID', - 'WORKFLOW_ID', - 'DOCUMENT_NAME', - 'DESCRIPTION', - 'NAME', - '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' - ])->getTasks()); - - $this->serviceBuilder->getBizProcScope()->task()->complete( - 2, - \Bitrix24\SDK\Services\Workflows\Common\WorkflowTaskCompleteStatusType::approved, - 'oook' - ); - - - return 0; - } -} - -$application = new Application(); -$application->add(new task($b24Service, $log)); -$application->run($input); diff --git a/examples/services/workflows/workflow.php b/examples/services/workflows/workflow.php deleted file mode 100644 index 776c1eaf..00000000 --- a/examples/services/workflows/workflow.php +++ /dev/null @@ -1,159 +0,0 @@ -#!/usr/bin/env php -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('.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_NAME'], (int)$_ENV['LOGS_LEVEL'])); -$log->pushProcessor(new MemoryUsageProcessor(true, true)); - -$webhookUrl = $_ENV['BITRIX24_WEBHOOK']; -$b24ServiceFactory = new ServiceBuilderFactory(new EventDispatcher(), $log); -// init bitrix24-php-sdk service with webhook credentials -$b24Service = $b24ServiceFactory->initFromWebhook($webhookUrl); - -#[AsCommand( - name: 'bitrix24-php-sdk:examples:workflows:workflow', - hidden: false -)] -class workflow extends Command -{ - private LoggerInterface $log; - private ServiceBuilder $serviceBuilder; - - public function __construct(ServiceBuilder $serviceBuilder, 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->log = $logger; - $this->serviceBuilder = $serviceBuilder; - parent::__construct(); - } - - protected function configure(): void - { - $this - ->setDescription('Example of work with workflows') - ->setHelp('Run workflow for contact') - ->addOption( - 'workflow-template-id', - null, - InputOption::VALUE_REQUIRED, - 'workflow template id', - ) - ->addOption( - 'contact-id', - null, - InputOption::VALUE_REQUIRED, - 'Bitrix24 contact id', - ); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - $workflowTemplateId = $input->getOption('workflow-template-id'); - $contactId = $input->getOption('contact-id'); - if ($workflowTemplateId === null) { - throw new InvalidArgumentException('Missing workflow template id, you must set workflow-template-id'); - } - if ($contactId === null) { - throw new InvalidArgumentException('Missing contact id, you must set contact-id'); - } - $output->writeln([ - 'Work with workflow example', - '', - sprintf('workflow template id: %s', $workflowTemplateId), - sprintf('contact id: %s', $contactId), - '', - 'run workflow for contact...' - ]); - - // run workflow - $workflowInstanceId = $this->serviceBuilder->getBizProcScope()->workflow()->start( - DocumentType::crmContact, - $workflowTemplateId, - $contactId, - )->getRunningWorkflowInstanceId(); - $output->writeln(sprintf('running workflow instance id: %s', $workflowInstanceId)); - - // get running workflow instance list - $workflowInstances = $this->serviceBuilder->getBizProcScope()->workflow()->instances( - [], - [], - [ - 'ENTITY' => DocumentType::crmContact->value - ] - )->getInstances(); - var_dump($workflowInstances); - - - // try to terminate workflow - $terminationResult = $this->serviceBuilder->getBizProcScope()->workflow()->terminate( - $workflowInstanceId, - 'terminated!' - ); - - var_dump($terminationResult->isSuccess()); - - - return 0; - } -} - -$application = new Application(); -$application->add(new workflow($b24Service, $log)); -$application->run($input); diff --git a/examples/webhook/.env b/examples/webhook/.env deleted file mode 100644 index 1355fb8e..00000000 --- a/examples/webhook/.env +++ /dev/null @@ -1,5 +0,0 @@ -# bitrix24 webhook url -BITRIX24_WEBHOOK_URL= -# monolog -LOG_LEVEL=100 -LOG_FILE_NAME=bitrix24-php-sdk.log diff --git a/examples/webhook/composer.json b/examples/webhook/composer.json index 03105bc5..f8462c44 100644 --- a/examples/webhook/composer.json +++ b/examples/webhook/composer.json @@ -10,9 +10,9 @@ } ], "require": { - "mesilov/bitrix24-php-sdk": "dev-371-publish-b24-php-sdk-beta-2", - "monolog/monolog": "3.5.*", - "symfony/dotenv": "7.0.*" + "mesilov/bitrix24-php-sdk": "dev-feature/390-prepare-publish-2-0", + "monolog/monolog": "^3", + "symfony/dotenv": "^7" }, "require-dev": { "roave/security-advisories": "dev-latest" diff --git a/examples/webhook/example.php b/examples/webhook/example.php index bc3098ac..72a5b825 100644 --- a/examples/webhook/example.php +++ b/examples/webhook/example.php @@ -2,29 +2,25 @@ declare(strict_types=1); use Bitrix24\SDK\Services\ServiceBuilderFactory; -use Monolog\Handler\StreamHandler; +use Symfony\Component\EventDispatcher\EventDispatcher; use Monolog\Logger; -use Monolog\Processor\IntrospectionProcessor; +use Monolog\Handler\StreamHandler; use Monolog\Processor\MemoryUsageProcessor; -use Symfony\Component\Dotenv\Dotenv; -use Symfony\Component\EventDispatcher\EventDispatcher; -require_once 'vendor/autoload.php'; +require_once 'vendor/autoload.php'; -// load credentials for work with bitrix24 portal -(new Dotenv())->loadEnv('.env'); -$webhookUrl = $_ENV['BITRIX24_WEBHOOK_URL']; +$webhookUrl = 'INSERT_HERE_YOUR_WEBHOOK_URL'; -// configure logger for debug queries $log = new Logger('bitrix24-php-sdk'); -$log->pushHandler(new StreamHandler($_ENV['LOG_FILE_NAME'], (int)$_ENV['LOG_LEVEL'])); +$log->pushHandler(new StreamHandler('bitrix24-php-sdk.log')); $log->pushProcessor(new MemoryUsageProcessor(true, true)); -$log->pushProcessor(new IntrospectionProcessor()); -// create factory for build service from multiple sources: webhook, request, bitrix24 account with oauth2.0 tokens +// create service builder factory $b24ServiceFactory = new ServiceBuilderFactory(new EventDispatcher(), $log); -// init bitrix24-php-sdk service with webhook credentials +// init bitrix24-php-sdk service from webhook $b24Service = $b24ServiceFactory->initFromWebhook($webhookUrl); -$deal = $b24Service->getCRMScope()->deal()->get(1)->deal(); -var_dump($deal->TITLE); \ No newline at end of file +// 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); From db898e5f77fc87e80777e4499bae94525b8c65b1 Mon Sep 17 00:00:00 2001 From: mesilov Date: Tue, 27 Aug 2024 01:34:56 +0600 Subject: [PATCH 131/138] Remove local application files and update examples Deleted outdated local application files including .env, activity-handler.php, and robot-handler.php. Updated README with detailed instructions and examples on working with webhooks and local applications. Added a new composer.json for dependency management in the local-application directory. Signed-off-by: mesilov --- README.md | 123 ++++++++- examples/application/local/.env | 8 - .../application/local/activity-handler.php | 156 ----------- examples/application/local/index.php | 254 ------------------ examples/application/local/robot-handler.php | 87 ------ examples/local-application/composer.json | 20 ++ examples/local-application/index.php | 36 +++ .../local => local-application}/install.php | 5 +- 8 files changed, 173 insertions(+), 516 deletions(-) delete mode 100644 examples/application/local/.env delete mode 100644 examples/application/local/activity-handler.php delete mode 100644 examples/application/local/index.php delete mode 100644 examples/application/local/robot-handler.php create mode 100644 examples/local-application/composer.json create mode 100644 examples/local-application/index.php rename examples/{application/local => local-application}/install.php (53%) diff --git a/README.md b/README.md index bbe60abe..b51d9dc2 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,8 @@ API - level features 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 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 @@ -77,6 +78,7 @@ Performance improvements 🚀 output: b24 response dto process: b24 entities, operate with immutable objects ``` + ## Documentation - [Bitrix24 API documentation - English](https://training.bitrix24.com/rest_help/) @@ -99,12 +101,20 @@ Add `"mesilov/bitrix24-php-sdk": "2.x"` to `composer.json` of your application. ## Examples ### Work with webhook + 1. Go to `/examples/webhook` folder 2. Open console and install dependencies + ```shell composer install ``` -3. Open example file and insert webhook url into `$webhookUrl` + +3. Open Bitrix24 portal: Developer resources → Other → Inbound webhook +4. Open example file and insert webhook url into `$webhookUrl` + +
+ see example.php file + ```php declare(strict_types=1); @@ -132,12 +142,103 @@ var_dump($b24Service->getMainScope()->main()->getCurrentUserProfile()->getUserPr // get deals list and address to first element var_dump($b24Service->getCRMScope()->lead()->list([], [], ['ID', 'TITLE'])->getLeads()[0]->TITLE); ``` -4. call php file in cli + +
+ +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 @@ -146,16 +247,22 @@ if you want to create application you can use production-ready contracts in name - `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 +- `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. +- `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. + +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. @@ -171,6 +278,7 @@ Call in command line ```shell make lint-phpstan ``` + ### PHP Static Analysis Tool – rector Call in command line for validate @@ -178,6 +286,7 @@ Call in command line for validate ```shell make lint-rector ``` + Call in command line for fix codebase ```shell diff --git a/examples/application/local/.env b/examples/application/local/.env deleted file mode 100644 index ef1ad926..00000000 --- a/examples/application/local/.env +++ /dev/null @@ -1,8 +0,0 @@ -# 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= \ No newline at end of file diff --git a/examples/application/local/activity-handler.php b/examples/application/local/activity-handler.php deleted file mode 100644 index fbb6af41..00000000 --- a/examples/application/local/activity-handler.php +++ /dev/null @@ -1,156 +0,0 @@ - -
-    Приложение работает, получили токены от Битрикс24:
-    
-
-bootEnv('.env'); - -if ($_SERVER['APP_DEBUG']) { - umask(0000); - - if (class_exists( - Debug::class - )) { - Debug::enable(); - } -} - - -try { - $log = new Logger('bitrix24-php-sdk-cli'); - $log->pushHandler(new StreamHandler($_ENV['LOGS_FILE_NAME'], (int)$_ENV['LOGS_LEVEL'])); - $log->pushProcessor(new MemoryUsageProcessor(true, true)); - - $req = Request::createFromGlobals(); - $log->debug('incoming request', [ - 'payload' => $req->request->all() - ]); - - $workflowReq = IncomingRobotRequest::initFromRequest($req); - - print_r($workflowReq); - - $b24ServiceFactory = new ServiceBuilderFactory(new EventDispatcher(), $log); - $appProfile = ApplicationProfile::initFromArray($_ENV); - - //AccessToken::initFromWorkflowRequest($req), - $b24Service = $b24ServiceFactory->initFromRequest( - $appProfile, - $workflowReq->auth->accessToken, - $workflowReq->auth->domain - ); - - $returnProp = [ - 'result_sum' => 5555 - ]; - - print('PROP' . PHP_EOL); - print_r($workflowReq->properties); - print_r($b24Service->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()); - - $b24Service->getBizProcScope()->activity()->log( - $workflowReq->eventToken, - 'hello from activity handler' - ); - - $res = $b24Service->getBizProcScope()->event()->send( - $workflowReq->eventToken, - $returnProp, - sprintf('debug result %s', print_r($returnProp, true)) - ); - $log->debug('ffffffff', [ - 'res' => $res->isSuccess() - ]); - -} catch (Throwable $exception) { - - $log->error(sprintf('error: %s', $exception->getMessage()), [ - 'trace' => $exception->getTraceAsString() - ]); - - print('ERRRRRRRRRORRRR!!!!'); - print($exception->getMessage() . PHP_EOL); - print_r($exception->getTraceAsString()); - -} - - -// Array -// ( -// [workflow_id] => 664fa13bbbb410.99176768 -// [code] => test_activity -// [document_id] => Array -// ( -// [0] => crm -// [1] => CCrmDocumentContact -// [2] => CONTACT_109286 -// ) -// -// [document_type] => Array -// ( -// [0] => crm -// [1] => CCrmDocumentContact -// [2] => CONTACT -// ) -// -// [event_token] => 664fa13bbbb410.99176768|A40364_79843_85254_57332|MS1ekdI0CvXi8ycL8qNIn96hak8JEndG.54020ce210345fb6eb12a79d75316d9430b42ccd9c1d82ab1a3bf8b064ec50e9 -// [properties] => Array -// ( -// [comment] => дефолтная строка - значение -// [amount] => 333 -// ) -// -// [use_subscription] => Y -// [timeout_duration] => 660 -// [ts] => 1716494651 - -// [auth] => Array -// ( - -// access token -// [access_token] => 4baf4f66006e13540058f18a000000100000009b41bce7ec85f07c3646c07e6d629e7c -// [refresh_token] => 3b2e7766006e13540058f18a000000100000003b31a96730e79dc7561c1d7d0b33933f -// [expires] => 1716498251 - -// endpoints -// [server_endpoint] => https://oauth.bitrix.info/rest/ -// [client_endpoint] => https://bitrix24-php-sdk-playground.bitrix24.ru/rest/ - -// scope -// [scope] => crm,bizproc,appform,baas,placement,user_brief,call,telephony - -// application status -// [status] => L - - -// [application_token] => f9ac5db5ad4adbdee13eb034207d8fbd -// [expires_in] => 3600 -// [domain] => bitrix24-php-sdk-playground.bitrix24.ru -// [member_id] => 010b6886ebc205e43ae65000ee00addb -// [user_id] => 16 -// ) -//) diff --git a/examples/application/local/index.php b/examples/application/local/index.php deleted file mode 100644 index 6a6e55d3..00000000 --- a/examples/application/local/index.php +++ /dev/null @@ -1,254 +0,0 @@ - -
-    Приложение работает, получили токены от Битрикс24:
-    
-
-bootEnv('.env'); - -if ($_SERVER['APP_DEBUG']) { - umask(0000); - - if (class_exists( - Debug::class - )) { - Debug::enable(); - } -} - -$request = Request::createFromGlobals(); - - -$log = new Logger('bitrix24-php-sdk-cli'); -$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); -$b24Service = $b24ServiceFactory->initFromRequest($appProfile, AuthToken::initFromPlacementRequest($request), $_REQUEST['DOMAIN']); - - -var_dump('Hello world'); - -var_dump(Bitrix24\SDK\Core\Credentials\Credentials::createFromPlacementRequest( - new \Bitrix24\SDK\Application\Requests\Placement\PlacementRequest($request), - $appProfile -)->getAuthToken()); -// -//$b64 = new \Symfony\Component\Mime\Encoder\Base64Encoder(); -//$str = $b64->encodeString(file_get_contents('bp-82.bpt')); - - -// run workflow -//var_dump($b24Service->getBizProcScope()->template()->delete(82)); - -//$templateId = $b24Service->getBizProcScope()->template()->add( -// WorkflowDocumentType::buildForContact(), -// 'Test template', -// 'Test template description', -// WorkflowAutoExecutionType::withoutAutoExecution, -// 'bp-82.bpt' -//)->getId(); -// -//$updateResult = $b24Service->getBizProcScope()->template()->update( -// $templateId, -// null, -// 'updated name', -// null, -// null, -// 'bp-82.bpt' -//)->isSuccess(); -// -//var_dump($updateResult); - - -// -// -//foreach ($b24Service->getBizProcScope()->activity()->list()->getActivities() as $activityCode) { -// var_dump($activityCode); -// var_dump($b24Service->getBizProcScope()->activity()->delete($activityCode)->isSuccess()); -//} -//$activityCode = 'test_activity'; -//$handlerUrl = 'https://' . $_SERVER['HTTP_HOST'] . '/activity-handler.php'; -//$b24AdminUserId = $b24Service->getMainScope()->main()->getCurrentUserProfile()->getUserProfile()->ID; -//$activityName = [ -// 'ru' => 'Название активити', -// 'en' => 'activity name' -//]; -//$activityDescription = [ -// 'ru' => 'Описание активити', -// 'en' => 'Activity description' -//]; -//$activityProperties = [ -// 'comment' => [ -// 'Name' => [ -// 'ru' => 'строка desc', -// 'en' => 'string desc' -// ], -// 'Description' => [ -// 'ru' => 'строка desc', -// 'en' => 'string desc' -// ], -// 'Type' => WorkflowPropertyType::string->name, -// 'Options' => null, -// 'Required' => 'N', -// 'Multiple' => 'N', -// 'Default' => 'дефолтная строка - значение' -// -// ], -// 'amount' => [ -// 'Name' => [ -// 'ru' => 'int значение', -// 'en' => 'int value' -// ], -// 'Description' => [ -// 'ru' => 'int значение пример', -// 'en' => 'int value example' -// ], -// 'Type' => WorkflowPropertyType::int->name, -// 'Options' => null, -// 'Required' => 'N', -// 'Multiple' => 'N', -// 'Default' => 333 -// ] -//]; -// -//$activityReturnProperties = [ -// 'result_sum' => [ -// 'Name' => [ -// 'ru' => 'int значение', -// 'en' => 'int value' -// ], -// 'Description' => [ -// 'ru' => 'int', -// 'en' => 'int' -// ], -// 'Type' => WorkflowPropertyType::int->name, -// 'Options' => null, -// 'Required' => 'N', -// 'Multiple' => 'N', -// 'Default' => 444 -// ] -//]; -// -// -//$addActivityResult = $b24Service->getBizProcScope()->activity()->add( -// $activityCode, -// $handlerUrl, -// $b24AdminUserId, -// $activityName, -// $activityDescription, -// true, -// $activityProperties, -// false, -// $activityReturnProperties, -// WorkflowDocumentType::buildForLead(), -// [] -//); -// -//var_dump($addActivityResult->getCoreResponse()->getResponseData()->getResult()); -// -// -// -//print('delete robots...' . PHP_EOL); -//foreach ($b24Service->getBizProcScope()->robot()->list()->getRobots() as $robotCode) { -// print_r($b24Service->getBizProcScope()->robot()->delete($robotCode)->isSuccess()); -//} -// -// -//$robotProperties = [ -// 'comment' => [ -// 'Name' => [ -// 'ru' => 'строка desc', -// 'en' => 'string desc' -// ], -// 'Description' => [ -// 'ru' => 'строка desc', -// 'en' => 'string desc' -// ], -// 'Type' => WorkflowPropertyType::string->name, -// 'Options' => null, -// 'Required' => 'N', -// 'Multiple' => 'N', -// 'Default' => 'дефолтная строка - значение' -// -// ], -// 'amount' => [ -// 'Name' => [ -// 'ru' => 'int значение', -// 'en' => 'int value' -// ], -// 'Description' => [ -// 'ru' => 'int значение пример', -// 'en' => 'int value example' -// ], -// 'Type' => WorkflowPropertyType::int->name, -// 'Options' => null, -// 'Required' => 'N', -// 'Multiple' => 'N', -// 'Default' => 333 -// ] -//]; -// -//$robotReturnProperties = [ -// 'result_sum' => [ -// 'Name' => [ -// 'ru' => 'int значение', -// 'en' => 'int value' -// ], -// 'Description' => [ -// 'ru' => 'int', -// 'en' => 'int' -// ], -// 'Type' => WorkflowPropertyType::int->name, -// 'Options' => null, -// 'Required' => 'N', -// 'Multiple' => 'N', -// 'Default' => 'дефолтная строка - значение' -// ] -//]; -// -//$handlerUrl = 'https://' . $_SERVER['HTTP_HOST'] . '/robot-handler.php'; -//var_dump($handlerUrl); -//print('install robots...' . PHP_EOL); -//$addResult = $b24Service->getBizProcScope()->robot()->add('test_r_1', $handlerUrl, -// 1, -// [ -// 'ru' => 'РОБОТ 1', -// 'en' => 'robot 1', -// ], -// true, -// $robotProperties, -// false, -// $robotReturnProperties -//); -// -//var_dump($addResult->isSuccess()); -//// -//var_dump($b24Service->getBizProcScope()->robot()->list()->getRobots()); -//// -// diff --git a/examples/application/local/robot-handler.php b/examples/application/local/robot-handler.php deleted file mode 100644 index ab923878..00000000 --- a/examples/application/local/robot-handler.php +++ /dev/null @@ -1,87 +0,0 @@ - -
-    Приложение работает, получили токены от Битрикс24:
-    
-
-bootEnv('.env'); - -if ($_SERVER['APP_DEBUG']) { - umask(0000); - - if (class_exists( - Debug::class - )) { - Debug::enable(); - } -} - - -try { - $log = new Logger('bitrix24-php-sdk-cli'); - $log->pushHandler(new StreamHandler($_ENV['LOGS_FILE_NAME'], (int)$_ENV['LOGS_LEVEL'])); - $log->pushProcessor(new MemoryUsageProcessor(true, true)); - - $req = Request::createFromGlobals(); - $log->debug('incoming request', [ - 'payload' => $req->request->all() - ]); - - $b24ServiceFactory = new ServiceBuilderFactory(new EventDispatcher(), $log); - $appProfile = ApplicationProfile::initFromArray($_ENV); - - - $rr = IncomingRobotRequest::initFromRequest($req); - - $b24Service = $b24ServiceFactory->initFromRequest( - $appProfile, - $rr->auth->accessToken, - $rr->auth->domain - ); - - $returnProp = [ - 'result_sum' => 5555 - ]; - - $res = $b24Service->getBizProcScope()->event()->send( - $rr->eventToken, - $returnProp, - sprintf('debug result %s', print_r($returnProp, true)) - ); - $log->debug('ffffffff', [ - 'res' => $res->isSuccess() - ]); - -} catch (Throwable $exception) { - - $log->error(sprintf('error: %s', $exception->getMessage()), [ - 'trace' => $exception->getTraceAsString() - ]); - - -} - - 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..64573a63 --- /dev/null +++ b/examples/local-application/index.php @@ -0,0 +1,36 @@ + +
+    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/application/local/install.php b/examples/local-application/install.php similarity index 53% rename from examples/application/local/install.php rename to examples/local-application/install.php index 31cd5b2a..f5812ca7 100644 --- a/examples/application/local/install.php +++ b/examples/local-application/install.php @@ -1,11 +1,8 @@
-    Установка приложения, получили токены от Битрикс24:
+    Application installation started, tokens from Bitrix24:
     
 
From e2285fb19d8f75e8e0d359db25ac0dbda244afda Mon Sep 17 00:00:00 2001 From: mesilov Date: Tue, 27 Aug 2024 01:43:09 +0600 Subject: [PATCH 132/138] Move "Sponsors" section down Relocated the "Sponsors" section to improve the document's structure. This ensures that sponsorship details are positioned closer to the contributors' section, enhancing logical flow. Signed-off-by: mesilov --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b51d9dc2..920713ba 100644 --- a/README.md +++ b/README.md @@ -84,10 +84,6 @@ Performance improvements 🚀 - [Bitrix24 API documentation - English](https://training.bitrix24.com/rest_help/) - [Internal documentation](docs/EN/documentation.md) for bitrix24-php-sdk -## Sponsors - -Help bitrix24-php-sdk by [boosty.to/bitrix24-php-sdk](https://boosty.to/bitrix24-php-sdk) - ## Requirements - php: >=8.2 @@ -347,6 +343,10 @@ 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 + +Help bitrix24-php-sdk by [boosty.to/bitrix24-php-sdk](https://boosty.to/bitrix24-php-sdk) + ## Need custom Bitrix24 application? Email to mesilov.maxim@gmail.com for private consultations or dedicated support. \ No newline at end of file From 17532dc3d6953e252defb698537981a203220228 Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 28 Aug 2024 00:54:41 +0600 Subject: [PATCH 133/138] Update copyright in files Signed-off-by: mesilov --- MIT-LICENSE.txt | 2 +- Makefile | 7 + bin/console | 9 + docs/EN/Services/bitrix24-php-sdk-methods.md | 320 +++++++++--------- examples/local-application/index.php | 10 + examples/local-application/install.php | 10 + examples/webhook/example.php | 10 + rector.php | 9 + src/Application/ApplicationStatus.php | 9 + .../ApplicationInstallationInterface.php | 10 + .../Entity/ApplicationInstallationStatus.php | 10 + ...tallationApplicationStatusChangedEvent.php | 9 + ...nstallationBitrix24PartnerChangedEvent.php | 9 + ...trix24PartnerContactPersonChangedEvent.php | 9 + .../ApplicationInstallationBlockedEvent.php | 9 + ...nInstallationContactPersonChangedEvent.php | 9 + .../ApplicationInstallationCreatedEvent.php | 9 + ...tionInstallationExternalIdChangedEvent.php | 9 + .../ApplicationInstallationFinishedEvent.php | 9 + ...llationPortalLicenseFamilyChangedEvent.php | 9 + ...stallationPortalUsersCountChangedEvent.php | 9 + .../ApplicationInstallationUnblockedEvent.php | 9 + ...pplicationInstallationUninstalledEvent.php | 9 + ...plicationInstallationNotFoundException.php | 9 + ...icationInstallationRepositoryInterface.php | 9 + .../Entity/Bitrix24AccountInterface.php | 9 + .../Entity/Bitrix24AccountStatus.php | 9 + ...trix24AccountApplicationInstalledEvent.php | 9 + ...ix24AccountApplicationUninstalledEvent.php | 9 + ...4AccountApplicationVersionUpdatedEvent.php | 9 + .../Events/Bitrix24AccountBlockedEvent.php | 9 + .../Events/Bitrix24AccountCreatedEvent.php | 9 + .../Events/Bitrix24AccountDeletedEvent.php | 9 + .../Bitrix24AccountDomainUrlChangedEvent.php | 9 + .../Events/Bitrix24AccountUnblockedEvent.php | 9 + .../Bitrix24AccountNotFoundException.php | 9 + .../Bitrix24AccountRepositoryInterface.php | 9 + .../Entity/Bitrix24PartnerInterface.php | 9 + .../Entity/Bitrix24PartnerStatus.php | 9 + .../Events/Bitrix24PartnerBlockedEvent.php | 9 + .../Events/Bitrix24PartnerCreatedEvent.php | 9 + .../Events/Bitrix24PartnerDeletedEvent.php | 9 + .../Bitrix24PartnerEmailChangedEvent.php | 9 + .../Bitrix24PartnerExternalIdChangedEvent.php | 9 + .../Bitrix24PartnerOpenLineIdChangedEvent.php | 9 + .../Bitrix24PartnerPartnerIdChangedEvent.php | 9 + .../Bitrix24PartnerPhoneChangedEvent.php | 9 + .../Bitrix24PartnerSiteChangedEvent.php | 9 + .../Bitrix24PartnerTitleChangedEvent.php | 9 + .../Events/Bitrix24PartnerUnblockedEvent.php | 9 + .../Bitrix24PartnerNotFoundException.php | 9 + .../Bitrix24PartnerRepositoryInterface.php | 9 + .../Entity/ContactPersonInterface.php | 9 + .../Entity/ContactPersonStatus.php | 9 + .../ContactPersons/Entity/FullName.php | 9 + .../Events/ContactPersonBlockedEvent.php | 9 + .../Events/ContactPersonCreatedEvent.php | 9 + .../Events/ContactPersonDeletedEvent.php | 9 + .../Events/ContactPersonEmailChangedEvent.php | 9 + .../ContactPersonEmailVerifiedEvent.php | 9 + .../ContactPersonFullNameChangedEvent.php | 9 + ...ntactPersonLinkedToExternalEntityEvent.php | 9 + .../ContactPersonMobilePhoneChangedEvent.php | 9 + .../ContactPersonMobilePhoneVerifiedEvent.php | 9 + .../Events/ContactPersonUnblockedEvent.php | 9 + .../ContactPersonNotFoundException.php | 9 + .../ContactPersonRepositoryInterface.php | 9 + .../AggregateRootEventsEmitterInterface.php | 9 + src/Application/PortalLicenseFamily.php | 9 + src/Application/Requests/AbstractRequest.php | 9 + .../Requests/Events/AbstractEventRequest.php | 9 + .../Requests/Events/EventAuthItem.php | 9 + .../Requests/Events/EventInterface.php | 9 + .../OnApplicationInstall/ApplicationData.php | 9 + .../OnApplicationInstall.php | 9 + .../ApplicationData.php | 9 + .../OnApplicationUninstall.php | 9 + .../Requests/Placement/PlacementRequest.php | 9 + src/Attributes/ApiBatchMethodMetadata.php | 9 + src/Attributes/ApiBatchServiceMetadata.php | 9 + src/Attributes/ApiEndpointMetadata.php | 9 + src/Attributes/ApiServiceMetadata.php | 9 + src/Attributes/Services/AttributesParser.php | 9 + src/Core/ApiClient.php | 9 + src/Core/ApiLevelErrorHandler.php | 9 + src/Core/Batch.php | 9 + src/Core/BulkItemsReader/BulkItemsReader.php | 9 + .../BulkItemsReaderBuilder.php | 9 + .../FilterWithBatchWithoutCountOrder.php | 9 + .../FilterWithoutBatchWithoutCountOrder.php | 9 + src/Core/Commands/Command.php | 9 + src/Core/Commands/CommandCollection.php | 9 + .../Contracts/AddedItemIdResultInterface.php | 9 + src/Core/Contracts/ApiClientInterface.php | 9 + .../Contracts/BatchOperationsInterface.php | 9 + .../Contracts/BulkItemsReaderInterface.php | 9 + src/Core/Contracts/CoreInterface.php | 9 + .../Contracts/DeletedItemResultInterface.php | 9 + .../Contracts/UpdatedItemResultInterface.php | 9 + src/Core/Core.php | 9 + src/Core/CoreBuilder.php | 9 + src/Core/Credentials/ApplicationProfile.php | 9 + src/Core/Credentials/AuthToken.php | 9 + src/Core/Credentials/Credentials.php | 9 + src/Core/Credentials/Endpoints.php | 9 + src/Core/Credentials/Scope.php | 9 + src/Core/Credentials/WebhookUrl.php | 9 + .../Exceptions/AuthForbiddenException.php | 9 + src/Core/Exceptions/BaseException.php | 9 + src/Core/Exceptions/FileNotFoundException.php | 9 + .../ImmutableResultViolationException.php | 9 + .../Exceptions/InvalidArgumentException.php | 9 + .../MethodConfirmWaitingException.php | 9 + .../Exceptions/MethodNotFoundException.php | 9 + .../OperationTimeLimitExceededException.php | 9 + .../QueryLimitExceededException.php | 9 + src/Core/Exceptions/TransportException.php | 9 + .../Exceptions/UnknownScopeCodeException.php | 9 + .../UserNotFoundOrIsNotActiveException.php | 9 + .../Exceptions/WrongAuthTypeException.php | 9 + src/Core/Fields/FieldsFilter.php | 9 + src/Core/Response/DTO/Pagination.php | 9 + src/Core/Response/DTO/RenewedAuthToken.php | 9 + src/Core/Response/DTO/ResponseData.php | 9 + src/Core/Response/DTO/Time.php | 9 + src/Core/Response/Response.php | 9 + src/Core/Result/AbstractItem.php | 9 + src/Core/Result/AbstractResult.php | 9 + src/Core/Result/AddedItemBatchResult.php | 9 + src/Core/Result/AddedItemResult.php | 9 + src/Core/Result/DeletedItemBatchResult.php | 9 + src/Core/Result/DeletedItemResult.php | 9 + src/Core/Result/EmptyResult.php | 9 + src/Core/Result/FieldsResult.php | 9 + src/Core/Result/UpdatedItemBatchResult.php | 9 + src/Core/Result/UpdatedItemResult.php | 9 + .../Result/UserInterfaceDialogCallResult.php | 9 + src/Events/AuthTokenRenewedEvent.php | 9 + src/Events/PortalDomainUrlChangedEvent.php | 9 + .../GenerateCoverageDocumentationCommand.php | 9 + .../Filesystem/Base64Encoder.php | 9 + .../RequestId/DefaultRequestIdGenerator.php | 9 + .../RequestId/RequestIdGeneratorInterface.php | 9 + .../TransportLayer/NetworkTimingsParser.php | 9 + .../TransportLayer/ResponseInfoParser.php | 9 + src/Services/AbstractBatchService.php | 9 + src/Services/AbstractService.php | 9 + src/Services/AbstractServiceBuilder.php | 9 + .../CRM/Activity/ActivityContentType.php | 9 + .../CRM/Activity/ActivityDirectionType.php | 9 + .../CRM/Activity/ActivityFetcherBuilder.php | 9 + .../CRM/Activity/ActivityNotifyType.php | 9 + .../CRM/Activity/ActivityPriority.php | 9 + src/Services/CRM/Activity/ActivityStatus.php | 9 + src/Services/CRM/Activity/ActivityType.php | 9 + .../CRM/Activity/ReadModel/EmailFetcher.php | 9 + .../Activity/ReadModel/OpenLineFetcher.php | 9 + .../Activity/ReadModel/VoximplantFetcher.php | 8 + .../CRM/Activity/ReadModel/WebFormFetcher.php | 8 + .../CRM/Activity/Result/ActivitiesResult.php | 9 + .../Activity/Result/ActivityItemResult.php | 9 + .../CRM/Activity/Result/ActivityResult.php | 9 + .../Result/Email/EmailActivityItemResult.php | 9 + .../CRM/Activity/Result/Email/EmailMeta.php | 9 + .../Activity/Result/Email/EmailSettings.php | 9 + .../OpenLine/OpenLineActivityItemResult.php | 9 + .../OpenLine/OpenLineProviderParams.php | 9 + .../Result/WebForm/VisitedPageItem.php | 8 + .../WebForm/WebFormActivityItemResult.php | 9 + .../Result/WebForm/WebFormFieldItem.php | 9 + .../Result/WebForm/WebFormMetadata.php | 9 + .../Result/WebForm/WebFormProviderParams.php | 9 + .../CRM/Activity/Service/Activity.php | 9 + src/Services/CRM/Activity/Service/Batch.php | 9 + src/Services/CRM/CRMServiceBuilder.php | 9 + .../CRM/Common/Result/AbstractCrmItem.php | 9 + .../CRM/Common/Result/DiscountType.php | 9 + .../Result/SystemFields/Types/Email.php | 9 + .../SystemFields/Types/EmailValueType.php | 9 + .../SystemFields/Types/InstantMessenger.php | 9 + .../Types/InstantMessengerValueType.php | 9 + .../Result/SystemFields/Types/Phone.php | 9 + .../SystemFields/Types/PhoneValueType.php | 9 + .../Result/SystemFields/Types/Website.php | 9 + .../SystemFields/Types/WebsiteValueType.php | 9 + .../CRM/Contact/Result/ContactItemResult.php | 9 + .../CRM/Contact/Result/ContactResult.php | 9 + .../Result/ContactUserfieldItemResult.php | 9 + .../Contact/Result/ContactUserfieldResult.php | 9 + .../Result/ContactUserfieldsResult.php | 9 + .../CRM/Contact/Result/ContactsResult.php | 9 + src/Services/CRM/Contact/Service/Batch.php | 9 + src/Services/CRM/Contact/Service/Contact.php | 9 + .../CRM/Contact/Service/ContactUserfield.php | 9 + src/Services/CRM/Deal/DealStageSemanticId.php | 9 + .../CRM/Deal/Result/DealCategoriesResult.php | 9 + .../Deal/Result/DealCategoryItemResult.php | 9 + .../CRM/Deal/Result/DealCategoryResult.php | 8 + .../Result/DealCategoryStageItemResult.php | 9 + .../Deal/Result/DealCategoryStagesResult.php | 9 + .../Deal/Result/DealCategoryStatusResult.php | 9 + .../CRM/Deal/Result/DealContactItemResult.php | 9 + .../Deal/Result/DealContactItemsResult.php | 9 + .../CRM/Deal/Result/DealItemResult.php | 9 + .../Deal/Result/DealProductRowItemResult.php | 9 + .../Deal/Result/DealProductRowItemsResult.php | 9 + src/Services/CRM/Deal/Result/DealResult.php | 9 + .../CRM/Deal/Result/DealSemanticStage.php | 9 + .../Deal/Result/DealUserfieldItemResult.php | 9 + .../CRM/Deal/Result/DealUserfieldResult.php | 9 + .../CRM/Deal/Result/DealUserfieldsResult.php | 9 + src/Services/CRM/Deal/Result/DealsResult.php | 9 + src/Services/CRM/Deal/Service/Batch.php | 9 + src/Services/CRM/Deal/Service/Deal.php | 9 + .../CRM/Deal/Service/DealCategory.php | 9 + .../CRM/Deal/Service/DealCategoryStage.php | 9 + src/Services/CRM/Deal/Service/DealContact.php | 9 + .../CRM/Deal/Service/DealProductRows.php | 9 + .../CRM/Deal/Service/DealUserfield.php | 9 + .../CRM/Duplicates/Result/DuplicateResult.php | 9 + .../CRM/Duplicates/Service/Duplicate.php | 9 + .../CRM/Duplicates/Service/EntityType.php | 9 + .../CRM/Item/Result/ItemItemResult.php | 9 + src/Services/CRM/Item/Result/ItemResult.php | 9 + src/Services/CRM/Item/Result/ItemsResult.php | 9 + src/Services/CRM/Item/Service/Batch.php | 9 + src/Services/CRM/Item/Service/Item.php | 9 + .../CRM/Lead/Result/LeadItemResult.php | 9 + src/Services/CRM/Lead/Result/LeadResult.php | 9 + src/Services/CRM/Lead/Result/LeadsResult.php | 9 + src/Services/CRM/Lead/Service/Batch.php | 9 + src/Services/CRM/Lead/Service/Lead.php | 9 + .../CRM/Product/Result/ProductItemResult.php | 9 + .../CRM/Product/Result/ProductResult.php | 9 + .../CRM/Product/Result/ProductsResult.php | 9 + src/Services/CRM/Product/Service/Batch.php | 9 + src/Services/CRM/Product/Service/Product.php | 9 + .../Settings/Result/SettingsModeResult.php | 9 + .../CRM/Settings/Service/Settings.php | 9 + .../UserfieldNameIsTooLongException.php | 9 + .../Exceptions/UserfieldNotFoundException.php | 9 + .../Result/AbstractUserfieldItemResult.php | 9 + .../Result/UserfieldTypeItemResult.php | 9 + .../Userfield/Result/UserfieldTypesResult.php | 9 + .../CRM/Userfield/Service/Userfield.php | 9 + .../Catalog/Result/CatalogItemResult.php | 9 + .../Catalog/Catalog/Result/CatalogResult.php | 9 + .../Catalog/Catalog/Result/CatalogsResult.php | 9 + .../Catalog/Catalog/Service/Catalog.php | 9 + .../Catalog/CatalogServiceBuilder.php | 9 + src/Services/Catalog/Common/ProductType.php | 9 + .../Common/Result/AbstractCatalogItem.php | 9 + .../Product/Result/ProductItemResult.php | 9 + .../Catalog/Product/Result/ProductResult.php | 9 + .../Catalog/Product/Result/ProductsResult.php | 9 + .../Catalog/Product/Service/Batch.php | 9 + .../Catalog/Product/Service/Product.php | 9 + src/Services/IM/IMServiceBuilder.php | 9 + src/Services/IM/Notify/Service/Notify.php | 9 + .../IMOpenLines/IMOpenLinesServiceBuilder.php | 9 + .../Result/AddedMessageItemResult.php | 9 + .../IMOpenLines/Result/JoinOpenLineResult.php | 9 + src/Services/IMOpenLines/Service/Network.php | 9 + .../Main/Common/EventHandlerMetadata.php | 9 + src/Services/Main/MainServiceBuilder.php | 9 + .../Main/Result/ApplicationInfoItemResult.php | 9 + .../Main/Result/ApplicationInfoResult.php | 9 + .../Main/Result/EventHandlerBindResult.php | 9 + .../Main/Result/EventHandlerItemResult.php | 9 + .../Main/Result/EventHandlerUnbindResult.php | 9 + .../Main/Result/EventHandlersResult.php | 9 + src/Services/Main/Result/EventListResult.php | 9 + .../Main/Result/IsUserAdminResult.php | 9 + .../Main/Result/MethodAffordabilityResult.php | 9 + src/Services/Main/Result/ServerTimeResult.php | 9 + .../Main/Result/UserProfileItemResult.php | 9 + .../Main/Result/UserProfileResult.php | 9 + src/Services/Main/Service/Event.php | 9 + src/Services/Main/Service/EventManager.php | 9 + src/Services/Main/Service/Main.php | 9 + .../Placement/PlacementServiceBuilder.php | 9 + .../Placement/Result/DeleteUserTypeResult.php | 9 + .../Placement/Result/PlacementBindResult.php | 9 + .../Result/PlacementLocationCodesResult.php | 9 + .../Result/PlacementLocationItemResult.php | 9 + .../Result/PlacementUnbindResult.php | 9 + .../PlacementsLocationInformationResult.php | 9 + .../Result/RegisterUserTypeResult.php | 9 + .../Result/UserFieldTypeItemResult.php | 9 + .../Placement/Result/UserFieldTypesResult.php | 9 + src/Services/Placement/Service/Placement.php | 9 + .../Service/PlacementLocationCode.php | 9 + .../Placement/Service/UserFieldType.php | 9 + src/Services/ServiceBuilder.php | 9 + src/Services/ServiceBuilderFactory.php | 9 + .../Result/TranscriptAttachItemResult.php | 9 + .../Call/Result/TranscriptAttachedResult.php | 9 + src/Services/Telephony/Call/Service/Batch.php | 9 + src/Services/Telephony/Call/Service/Call.php | 9 + .../Telephony/Common/CallFailedCode.php | 9 + src/Services/Telephony/Common/CallType.php | 9 + src/Services/Telephony/Common/CrmEntity.php | 9 + .../Telephony/Common/CrmEntityType.php | 9 + src/Services/Telephony/Common/PbxType.php | 9 + .../Common/SipRegistrationStatus.php | 9 + .../Common/TelephonyCallStatusCode.php | 9 + .../Telephony/Common/TranscriptMessage.php | 9 + .../Common/TranscriptMessageSide.php | 9 + .../OnExternalCallBackStart.php | 9 + .../OnExternalCallBackStartEventPayload.php | 9 + .../OnExternalCallStart.php | 9 + .../OnExternalCallStartEventPayload.php | 9 + .../OnVoximplantCallEnd.php | 9 + .../OnVoximplantCallEndEventPayload.php | 9 + .../OnVoximplantCallInit.php | 9 + .../OnVoximplantCallInitEventPayload.php | 9 + .../OnVoximplantCallStart.php | 9 + .../OnVoximplantCallStartEventPayload.php | 9 + .../Events/TelephonyEventsFabric.php | 9 + .../CallRecordFileUploadedItemResult.php | 9 + .../Result/CallRecordFileUploadedResult.php | 9 + .../Result/CallRecordUploadUrlItemResult.php | 9 + .../Result/CallRecordUploadUrlResult.php | 9 + .../Result/ExternalCallFinishedItemResult.php | 9 + .../Result/ExternalCallFinishedResult.php | 10 + .../ExternalCallRegisteredItemResult.php | 9 + .../Result/ExternalCallRegisteredResult.php | 9 + .../Result/SearchCrmEntitiesItemResult.php | 9 + .../Result/SearchCrmEntitiesResult.php | 9 + .../Result/UserDigestItemResult.php | 9 + .../Telephony/ExternalCall/Service/Batch.php | 9 + .../ExternalCall/Service/ExternalCall.php | 9 + .../Result/ExternalLineAddItemResult.php | 9 + .../Result/ExternalLineAddedResult.php | 9 + .../Result/ExternalLineItemResult.php | 9 + .../Result/ExternalLinesResult.php | 9 + .../Telephony/ExternalLine/Service/Batch.php | 9 + .../ExternalLine/Service/ExternalLine.php | 9 + .../Telephony/TelephonyServiceBuilder.php | 9 + .../Result/VoximplantInfoCallItemResult.php | 9 + .../Result/VoximplantInfoCallResult.php | 9 + .../Voximplant/InfoCall/Service/Batch.php | 9 + .../Voximplant/InfoCall/Service/InfoCall.php | 9 + .../Result/VoximplantLineIdItemResult.php | 9 + .../Line/Result/VoximplantLineIdResult.php | 9 + .../Line/Result/VoximplantLineItemResult.php | 9 + .../Line/Result/VoximplantLinesResult.php | 9 + .../Voximplant/Line/Service/Batch.php | 9 + .../Voximplant/Line/Service/Line.php | 9 + .../Result/SipConnectorStatusItemResult.php | 9 + .../Sip/Result/SipConnectorStatusResult.php | 9 + .../Sip/Result/SipLineAddedResult.php | 9 + .../Sip/Result/SipLineItemResult.php | 9 + .../Sip/Result/SipLineStatusItemResult.php | 9 + .../Sip/Result/SipLineStatusResult.php | 9 + .../Voximplant/Sip/Result/SipLinesResult.php | 9 + .../Voximplant/Sip/Service/Batch.php | 9 + .../Telephony/Voximplant/Sip/Service/Sip.php | 9 + .../Result/VoximplantVoiceItemResult.php | 9 + .../Voices/Result/VoximplantVoicesResult.php | 9 + .../Voximplant/TTS/Voices/Service/Batch.php | 9 + .../Voximplant/TTS/Voices/Service/Voices.php | 9 + .../Url/Result/VoximplantPagesItemResult.php | 9 + .../Url/Result/VoximplantPagesResult.php | 9 + .../Voximplant/Url/Service/Batch.php | 9 + .../Telephony/Voximplant/Url/Service/Url.php | 9 + .../VoximplantUserSettingsItemResult.php | 9 + .../Result/VoximplantUserSettingsResult.php | 9 + .../Voximplant/User/Service/Batch.php | 9 + .../Voximplant/User/Service/User.php | 9 + .../Voximplant/VoximplantServiceBuilder.php | 9 + src/Services/User/Result/UserItemResult.php | 9 + src/Services/User/Result/UserResult.php | 9 + src/Services/User/Result/UsersResult.php | 9 + src/Services/User/Service/User.php | 9 + src/Services/User/UserServiceBuilder.php | 9 + .../Result/UserConsentAgreementItemResult.php | 9 + .../Result/UserConsentAgreementResult.php | 9 + .../UserConsentAgreementTextItemResult.php | 9 + .../Result/UserConsentAgreementTextResult.php | 9 + .../Result/UserConsentAgreementsResult.php | 9 + .../UserConsent/Service/UserConsent.php | 9 + .../Service/UserConsentAgreement.php | 9 + .../UserConsent/UserConsentServiceBuilder.php | 9 + .../Activity/Result/AddedActivityResult.php | 9 + .../Result/AddedMessageToLogResult.php | 9 + .../Activity/Result/UpdateActivityResult.php | 9 + .../Result/WorkflowActivitiesResult.php | 9 + .../Workflows/Activity/Service/Activity.php | 9 + .../Workflows/Activity/Service/Batch.php | 9 + src/Services/Workflows/Common/Auth.php | 9 + .../Workflows/Common/DocumentType.php | 9 + .../Common/WorkflowAutoExecutionType.php | 9 + .../Workflows/Common/WorkflowDocumentId.php | 9 + .../Workflows/Common/WorkflowDocumentType.php | 9 + .../Workflows/Common/WorkflowPropertyType.php | 9 + .../Common/WorkflowTaskActivityType.php | 9 + .../Common/WorkflowTaskCompleteStatusType.php | 9 + .../Common/WorkflowTaskStatusType.php | 9 + .../Common/WorkflowTaskUserStatusType.php | 9 + .../Event/Result/EventSendResult.php | 9 + .../Workflows/Event/Service/Batch.php | 9 + .../Workflows/Event/Service/Event.php | 9 + ...tivityOrRobotAlreadyInstalledException.php | 9 + ...ivityOrRobotValidationFailureException.php | 9 + .../WorkflowTaskAlreadyCompletedException.php | 9 + .../Robot/Request/IncomingRobotRequest.php | 9 + .../Robot/Result/AddedRobotResult.php | 9 + .../Robot/Result/UpdateRobotResult.php | 9 + .../Robot/Result/WorkflowRobotsResult.php | 9 + .../Workflows/Robot/Service/Robot.php | 9 + .../Result/WorkflowTaskCompleteResult.php | 9 + .../Task/Result/WorkflowTaskItemResult.php | 9 + .../Task/Result/WorkflowTasksResult.php | 9 + src/Services/Workflows/Task/Service/Batch.php | 9 + src/Services/Workflows/Task/Service/Task.php | 9 + .../Result/WorkflowTemplateItemResult.php | 9 + .../Result/WorkflowTemplatesResult.php | 9 + .../Workflows/Template/Service/Batch.php | 9 + .../Workflows/Template/Service/Template.php | 9 + .../Request/IncomingWorkflowRequest.php | 9 + .../Result/WorkflowInstanceItemResult.php | 9 + .../Result/WorkflowInstanceStartResult.php | 9 + .../Result/WorkflowInstancesResult.php | 9 + .../Workflow/Result/WorkflowKillResult.php | 9 + .../Result/WorkflowTerminationResult.php | 9 + .../Workflows/Workflow/Service/Batch.php | 9 + .../Workflows/Workflow/Service/Workflow.php | 9 + .../Workflows/WorkflowsServiceBuilder.php | 9 + .../ApplicationInstallationInterfaceTest.php | 9 + ...ionInstallationRepositoryInterfaceTest.php | 9 + .../Entity/Bitrix24AccountInterfaceTest.php | 9 + ...Bitrix24AccountRepositoryInterfaceTest.php | 9 + .../Entity/Bitrix24PartnerInterfaceTest.php | 9 + ...Bitrix24PartnerRepositoryInterfaceTest.php | 9 + .../Entity/ContactPersonInterfaceTest.php | 9 + .../ContactPersonRepositoryInterfaceTest.php | 9 + .../ApplicationCredentialsProvider.php | 9 + .../AuthTokenFileStorage.php | 9 + .../AuthTokenRepositoryInterface.php | 9 + tests/ApplicationBridge/index.php | 9 + tests/ApplicationBridge/install.php | 8 + tests/Builders/DemoDataGenerator.php | 9 + .../Services/CRM/PhoneCollectionBuilder.php | 9 + .../Services/CRM/PhoneNumberBuilder.php | 9 + .../CustomBitrix24Assertions.php | 9 + .../Core/BatchGetTraversableTest.php | 9 + tests/Integration/Core/BatchTest.php | 9 + .../FilterWithBatchWithoutCountOrderTest.php | 9 + ...ilterWithoutBatchWithoutCountOrderTest.php | 9 + tests/Integration/Core/CoreTest.php | 9 + tests/Integration/Fabric.php | 9 + .../Activity/ReadModel/EmailFetcherTest.php | 9 + .../ReadModel/OpenLineFetcherTest.php | 9 + .../ReadModel/VoximplantFetcherTest.php | 9 + .../Activity/ReadModel/WebFormFetcherTest.php | 9 + .../CRM/Activity/Service/ActivityTest.php | 9 + .../CRM/Activity/Service/BatchTest.php | 9 + .../CRM/Contact/Service/ContactBatchTest.php | 9 + .../CRM/Contact/Service/ContactTest.php | 9 + .../Contact/Service/ContactUserfieldTest.php | 9 + .../Service/ContactUserfieldUseCaseTest.php | 9 + .../Services/CRM/Deal/Service/BatchTest.php | 9 + .../Deal/Service/DealCategoryStageTest.php | 9 + .../CRM/Deal/Service/DealCategoryTest.php | 9 + .../CRM/Deal/Service/DealContactTest.php | 9 + .../CRM/Deal/Service/DealProductRowsTest.php | 9 + .../Services/CRM/Deal/Service/DealTest.php | 9 + .../CRM/Deal/Service/DealUserfieldTest.php | 9 + .../Deal/Service/DealUserfieldUseCaseTest.php | 9 + .../CRM/Duplicates/Service/DuplicateTest.php | 9 + .../Services/CRM/Lead/Service/BatchTest.php | 9 + .../Services/CRM/Lead/Service/LeadTest.php | 9 + .../CRM/Products/Service/ProductsTest.php | 9 + .../CRM/Userfield/Service/UserfieldTest.php | 9 + .../Catalog/Catalog/Service/CatalogTest.php | 9 + .../Catalog/Product/Service/ProductTest.php | 9 + .../Services/IM/Service/NotifyTest.php | 9 + .../IMOpenLines/Service/NetworkTest.php | 9 + .../Services/Main/Service/MainTest.php | 9 + .../Placement/Service/PlacementTest.php | 9 + .../Telephony/Call/Service/CallTest.php | 9 + .../ExternalCall/Service/ExternalCallTest.php | 9 + .../ExternalLine/Service/ExternalLineTest.php | 9 + .../InfoCall/Service/InfoCallTest.php | 9 + .../Voximplant/Line/Service/LineTest.php | 9 + .../Telephony/Voximplant/Sip/SipTest.php | 9 + .../TTS/Voices/Service/VoicesTest.php | 9 + .../Voximplant/Url/Service/UrlTest.php | 9 + .../Telephony/Voximplant/User/UserTest.php | 9 + .../Services/User/Service/UserTest.php | 9 + .../Service/UserConsentAgreementTest.php | 9 + .../UserConsent/Service/UserConsentTest.php | 9 + tests/Temp/OperatingTimingTest.php | 42 ++- .../Application/ApplicationStatusTest.php | 9 + ...onInterfaceReferenceImplementationTest.php | 9 + ...tallationReferenceEntityImplementation.php | 9 + ...onInstallationRepositoryImplementation.php | 9 + ...stallationRepositoryImplementationTest.php | 9 + ...ntInterfaceReferenceImplementationTest.php | 9 + ...24AccountReferenceEntityImplementation.php | 9 + ...itrix24AccountRepositoryImplementation.php | 9 + ...x24AccountRepositoryImplementationTest.php | 9 + ...erInterfaceReferenceImplementationTest.php | 9 + ...24PartnerReferenceEntityImplementation.php | 9 + ...itrix24PartnerRepositoryImplementation.php | 9 + ...x24PartnerRepositoryImplementationTest.php | 9 + ...onInterfaceReferenceImplementationTest.php | 9 + ...actPersonReferenceEntityImplementation.php | 9 + ...yContactPersonRepositoryImplementation.php | 9 + ...tactPersonRepositoryImplementationTest.php | 9 + tests/Unit/Core/ApiLevelErrorHandlerTest.php | 9 + tests/Unit/Core/CoreBuilderTest.php | 9 + .../Credentials/ApplicationProfileTest.php | 9 + .../Unit/Core/Credentials/CredentialsTest.php | 9 + tests/Unit/Core/Credentials/ScopeTest.php | 9 + .../Unit/Core/Credentials/WebhookUrlTest.php | 9 + tests/Unit/Core/Response/DTO/TimeTest.php | 9 + tests/Unit/Core/Result/AbstractItemTest.php | 9 + .../DefaultRequestIdGeneratorTest.php | 9 + .../Services/CRM/CRMServiceBuilderTest.php | 9 + .../Unit/Services/IM/IMServiceBuilderTest.php | 9 + .../Services/Main/MainServiceBuilderTest.php | 9 + tests/Unit/Services/ServiceBuilderTest.php | 9 + tests/Unit/Stubs/NullBatch.php | 9 + tests/Unit/Stubs/NullBulkItemsReader.php | 9 + tests/Unit/Stubs/NullCore.php | 9 + tests/bootstrap.php | 9 + tools/Commands/CopyPropertyValues.php | 9 + tools/Commands/GenerateContactsCommand.php | 11 +- .../PerformanceBenchmarks/ListCommand.php | 9 + .../Commands/ShowFieldsDescriptionCommand.php | 9 + 532 files changed, 4946 insertions(+), 180 deletions(-) diff --git a/MIT-LICENSE.txt b/MIT-LICENSE.txt index 109e678b..ab879502 100644 --- a/MIT-LICENSE.txt +++ b/MIT-LICENSE.txt @@ -1,4 +1,4 @@ -Copyright 2022 Maxim Mesilov +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 index 1e8bffbb..963281b6 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,10 @@ +# 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/^/ - /' diff --git a/bin/console b/bin/console index 8e58fd68..b94007cc 100644 --- a/bin/console +++ b/bin/console @@ -1,6 +1,15 @@ #!/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; diff --git a/docs/EN/Services/bitrix24-php-sdk-methods.md b/docs/EN/Services/bitrix24-php-sdk-methods.md index ef1e5489..1ce25734 100644 --- a/docs/EN/Services/bitrix24-php-sdk-methods.md +++ b/docs/EN/Services/bitrix24-php-sdk-methods.md @@ -2,163 +2,163 @@ | **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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L35-L38)
Return type
[`Bitrix24\SDK\Services\Main\Result\ServerTimeResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L52-L55)
Return type
[`Bitrix24\SDK\Services\Main\Result\UserProfileResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L70-L75)
Return type
[`Bitrix24\SDK\Core\Response\Response`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L90-L95)
Return type
[`Bitrix24\SDK\Core\Response\Response`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L110-L117)
Return type
[`Bitrix24\SDK\Services\Main\Result\MethodAffordabilityResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L148-L151)
Return type
[`Bitrix24\SDK\Core\Response\Response`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L203-L206)
Return type
[`Bitrix24\SDK\Core\Response\Response`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L220-L223)
Return type
[`Bitrix24\SDK\Services\Main\Result\ApplicationInfoResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L237-L240)
Return type
[`Bitrix24\SDK\Services\Main\Result\IsUserAdminResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Catalog/Service/Catalog.php#L32-L35)
Return type
[`Bitrix24\SDK\Services\Catalog\Catalog\Result\CatalogResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Catalog/Service/Catalog.php#L49-L57)
Return type
[`Bitrix24\SDK\Services\Catalog\Catalog\Result\CatalogsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Catalog/Service/Catalog.php#L72-L75)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Product/Service/Product.php#L46-L49)
Return type
[`Bitrix24\SDK\Services\Catalog\Product\Result\ProductResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Product/Service/Product.php#L63-L69)
Return type
[`Bitrix24\SDK\Services\Catalog\Product\Result\ProductResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Product/Service/Product.php#L83-L86)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Product/Service/Product.php#L100-L108)
Return type
[`Bitrix24\SDK\Services\Catalog\Product\Result\ProductsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Product/Service/Product.php#L122-L133)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Settings/Service/Settings.php#L28-L31)
Return type
[`Bitrix24\SDK\Services\CRM\Settings\Result\SettingsModeResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Userfield/Service/Userfield.php#L32-L35)
Return type
[`Bitrix24\SDK\Services\CRM\Userfield\Result\UserfieldTypesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Userfield/Service/Userfield.php#L68-L71)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategory.php#L46-L56)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategory.php#L74-L84)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategory.php#L100-L103)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategory.php#L118-L121)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealCategoryResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategory.php#L141-L144)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategory.php#L163-L173)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealCategoryResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategory.php#L225-L235)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealCategoryStatusResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategory.php#L260-L271)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Core/Result/UpdatedItemResult.php)| -|`catalog`|[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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategoryStage.php#L29-L39)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealCategoryStagesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/Deal.php#L96-L107)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/Deal.php#L125-L135)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/Deal.php#L172-L175)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/Deal.php#L196-L209)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/Deal.php#L268-L280)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealProductRows.php#L36-L59)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealProductRowItemsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealProductRows.php#L99-L110)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Core/Result/UpdatedItemResult.php)| -|`catalog`|[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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealUserfield.php#L78-L89)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealUserfieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Result/DealUserfieldsResult.php)| -|`catalog`|[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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealUserfield.php#L130-L150)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Core/Result/AddedItemResult.php)| -|`catalog`|[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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealUserfield.php#L168-L178)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Core/Result/DeletedItemResult.php)| -|`catalog`|[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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealUserfield.php#L195-L205)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealUserfieldResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Result/DealUserfieldResult.php)| -|`catalog`|[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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealUserfield.php#L223-L234)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealContact.php#L40-L55)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealContact.php#L69-L72)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealContact.php#L90-L100)
Return type
[`Bitrix24\SDK\Services\CRM\Deal\Result\DealContactItemsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealContact.php#L118-L128)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealContact.php#L151-L162)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealContact.php#L181-L194)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/Contact.php#L108-L119)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/Contact.php#L137-L147)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/Contact.php#L163-L166)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/Contact.php#L184-L194)
Return type
[`Bitrix24\SDK\Services\CRM\Contact\Result\ContactResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/Contact.php#L312-L325)
Return type
[`Bitrix24\SDK\Services\CRM\Contact\Result\ContactsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/Contact.php#L392-L404)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/ContactUserfield.php#L76-L87)
Return type
[`Bitrix24\SDK\Services\CRM\Contact\Result\ContactUserfieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/ContactUserfield.php#L128-L148)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/ContactUserfield.php#L166-L176)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/ContactUserfield.php#L193-L203)
Return type
[`Bitrix24\SDK\Services\CRM\Contact\Result\ContactUserfieldResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/ContactUserfield.php#L221-L232)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L101-L111)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L129-L139)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L155-L158)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L176-L186)
Return type
[`Bitrix24\SDK\Services\CRM\Activity\Result\ActivityResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L297-L310)
Return type
[`Bitrix24\SDK\Services\CRM\Activity\Result\ActivitiesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L373-L384)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Product/Service/Product.php#L78-L88)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Product/Service/Product.php#L106-L116)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Product/Service/Product.php#L134-L137)
Return type
[`Bitrix24\SDK\Services\CRM\Product\Result\ProductResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Product/Service/Product.php#L153-L156)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Product/Service/Product.php#L177-L190)
Return type
[`Bitrix24\SDK\Services\CRM\Product\Result\ProductsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Product/Service/Product.php#L231-L242)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Lead/Service/Lead.php#L115-L126)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Lead/Service/Lead.php#L144-L154)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Lead/Service/Lead.php#L170-L173)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Lead/Service/Lead.php#L191-L194)
Return type
[`Bitrix24\SDK\Services\CRM\Lead\Result\LeadResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Lead/Service/Lead.php#L215-L228)
Return type
[`Bitrix24\SDK\Services\CRM\Lead\Result\LeadsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Lead/Service/Lead.php#L307-L319)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Item/Service/Item.php#L49-L60)
Return type
[`Bitrix24\SDK\Services\CRM\Item\Result\ItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Item/Service/Item.php#L79-L86)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Item/Service/Item.php#L103-L106)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Item/Service/Item.php#L121-L124)
Return type
[`Bitrix24\SDK\Services\CRM\Item\Result\ItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Item/Service/Item.php#L139-L153)
Return type
[`Bitrix24\SDK\Services\CRM\Item\Result\ItemsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Item/Service/Item.php#L168-L180)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Duplicates/Service/Duplicate.php#L52-L60)
Return type
[`Bitrix24\SDK\Services\CRM\Duplicates\Result\DuplicateResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Activity/Service/Activity.php#L46-L52)
Return type
[`Bitrix24\SDK\Services\Workflows\Activity\Result\AddedMessageToLogResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Activity/Service/Activity.php#L66-L69)
Return type
[`Bitrix24\SDK\Services\Workflows\Activity\Result\WorkflowActivitiesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Activity/Service/Activity.php#L96-L123)
Return type
[`Bitrix24\SDK\Services\Workflows\Activity\Result\AddedActivityResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Activity/Service/Activity.php#L138-L144)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Activity/Service/Activity.php#L171-L225)
Return type
[`Bitrix24\SDK\Services\Workflows\Activity\Result\UpdateActivityResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Template/Service/Template.php#L48-L63)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Template/Service/Template.php#L83-L118)
Return type
[``](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/)| -|`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/feature/390-prepare-publish-2-0/src/Services/Workflows/Template/Service/Template.php#L136-L141)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Template/Service/Template.php#L155-L168)
Return type
[`Bitrix24\SDK\Services\Workflows\Template\Result\WorkflowTemplatesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Robot/Service/Robot.php#L48-L69)
Return type
[`Bitrix24\SDK\Services\Workflows\Robot\Result\AddedRobotResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Robot/Service/Robot.php#L83-L86)
Return type
[`Bitrix24\SDK\Services\Workflows\Robot\Result\WorkflowRobotsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Robot/Service/Robot.php#L101-L107)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Robot/Service/Robot.php#L124-L166)
Return type
[`Bitrix24\SDK\Services\Workflows\Robot\Result\UpdateRobotResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Workflow/Service/Workflow.php#L43-L48)
Return type
[`Bitrix24\SDK\Services\Workflows\Workflow\Result\WorkflowKillResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Workflow/Service/Workflow.php#L61-L67)
Return type
[`Bitrix24\SDK\Services\Workflows\Workflow\Result\WorkflowTerminationResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Workflow/Service/Workflow.php#L83-L135)
Return type
[`Bitrix24\SDK\Services\Workflows\Workflow\Result\WorkflowInstanceStartResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Workflow/Service/Workflow.php#L150-L165)
Return type
[`Bitrix24\SDK\Services\Workflows\Workflow\Result\WorkflowInstancesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Task/Service/Task.php#L54-L62)
Return type
[`Bitrix24\SDK\Services\Workflows\Task\Result\WorkflowTaskCompleteResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Task/Service/Task.php#L124-L134)
Return type
[`Bitrix24\SDK\Services\Workflows\Task\Result\WorkflowTasksResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Event/Service/Event.php#L41-L55)
Return type
[`Bitrix24\SDK\Services\Workflows\Event\Result\EventSendResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/User/Service/User.php#L34-L37)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/User/Service/User.php#L50-L53)
Return type
[`Bitrix24\SDK\Services\User\Result\UserResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/User/Service/User.php#L68-L83)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/User/Service/User.php#L95-L107)
Return type
[`Bitrix24\SDK\Services\User\Result\UsersResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/User/Service/User.php#L120-L128)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/User/Service/User.php#L142-L145)
Return type
[`Bitrix24\SDK\Services\User\Result\UsersResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/User/Service/User.php#L54-L59)
Return type
[`Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/User/Service/User.php#L75-L80)
Return type
[`Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/User/Service/User.php#L97-L104)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\User\Result\VoximplantUserSettingsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/Url/Service/Url.php#L41-L44)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\Url\Result\VoximplantPagesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/Line/Service/Line.php#L41-L46)
Return type
[`Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/Line/Service/Line.php#L58-L61)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\Line\Result\VoximplantLinesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/Line/Service/Line.php#L75-L78)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\Line\Result\VoximplantLineIdResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/Line/Service/Line.php#L94-L99)
Return type
[`Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/TTS/Voices/Service/Voices.php#L43-L46)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\TTS\Voices\Result\VoximplantVoicesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/Sip/Service/Sip.php#L48-L51)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result\SipConnectorStatusResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/Sip/Service/Sip.php#L65-L80)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result\SipLineAddedResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/Sip/Service/Sip.php#L96-L101)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/Sip/Service/Sip.php#L116-L119)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result\SipLinesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/Sip/Service/Sip.php#L136-L141)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\Sip\Result\SipLineStatusResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/Sip/Service/Sip.php#L156-L191)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/InfoCall/Service/InfoCall.php#L47-L55)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\InfoCall\Result\VoximplantInfoCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Voximplant/InfoCall/Service/InfoCall.php#L62-L69)
Return type
[`Bitrix24\SDK\Services\Telephony\Voximplant\InfoCall\Result\VoximplantInfoCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/Call/Service/Call.php#L45-L67)
Return type
[`Bitrix24\SDK\Services\Telephony\Call\Result\TranscriptAttachedResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/ExternalCall/Service/ExternalCall.php#L87-L98)
Return type
[`Bitrix24\SDK\Services\Telephony\ExternalCall\Result\CallRecordFileUploadedResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/ExternalCall/Service/ExternalCall.php#L147-L179)
Return type
[`Bitrix24\SDK\Services\Telephony\ExternalCall\Result\ExternalCallRegisteredResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/ExternalCall/Service/ExternalCall.php#L211-L217)
Return type
[`Bitrix24\SDK\Services\Telephony\ExternalCall\Result\SearchCrmEntitiesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/ExternalCall/Service/ExternalCall.php#L276-L299)
Return type
[`Bitrix24\SDK\Services\Telephony\ExternalCall\Result\ExternalCallFinishedResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/ExternalCall/Service/ExternalCall.php#L315-L322)
Return type
[`Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/ExternalCall/Service/ExternalCall.php#L338-L345)
Return type
[`Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/ExternalLine/Service/ExternalLine.php#L47-L54)
Return type
[`Bitrix24\SDK\Services\Telephony\ExternalLine\Result\ExternalLineAddedResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/ExternalLine/Service/ExternalLine.php#L68-L73)
Return type
[`Bitrix24\SDK\Core\Result\EmptyResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/ExternalLine/Service/ExternalLine.php#L87-L90)
Return type
[`Bitrix24\SDK\Services\Telephony\ExternalLine\Result\ExternalLinesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IM/Notify/Service/Notify.php#L35-L55)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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 system notification|[`Bitrix24\SDK\Services\IM\Notify\Service\Notify::fromPersonal`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Services/IM/Notify/Service/Notify.php#L62-L82)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IM/Notify/Service/Notify.php#L89-L103)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IM/Notify/Service/Notify.php#L147-L158)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IM/Notify/Service/Notify.php#L165-L177)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IM/Notify/Service/Notify.php#L184-L196)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/UserConsent/Service/UserConsent.php#L33-L36)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/UserConsent/Service/UserConsentAgreement.php#L31-L34)
Return type
[`Bitrix24\SDK\Services\UserConsent\Result\UserConsentAgreementsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/UserConsent/Service/UserConsentAgreement.php#L46-L61)
Return type
[`Bitrix24\SDK\Services\UserConsent\Result\UserConsentAgreementTextResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IMOpenLines/Service/Network.php#L29-L39)
Return type
[`Bitrix24\SDK\Services\IMOpenLines\Result\JoinOpenLineResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IMOpenLines/Service/Network.php#L49-L71)
Return type
[`Bitrix24\SDK\Services\IMOpenLines\Result\AddedMessageItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Event.php#L37-L45)
Return type
[`Bitrix24\SDK\Services\Main\Result\EventListResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Event.php#L60-L76)
Return type
[`Bitrix24\SDK\Services\Main\Result\EventHandlerBindResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Event.php#L91-L103)
Return type
[`Bitrix24\SDK\Services\Main\Result\EventHandlerUnbindResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Event.php#L116-L119)
Return type
[`Bitrix24\SDK\Core\Response\Response`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Event.php#L133-L136)
Return type
[`Bitrix24\SDK\Services\Main\Result\EventHandlersResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/UserFieldType.php#L36-L49)
Return type
[`Bitrix24\SDK\Services\Placement\Result\RegisterUserTypeResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/UserFieldType.php#L63-L68)
Return type
[`Bitrix24\SDK\Services\Placement\Result\UserFieldTypesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/UserFieldType.php#L87-L100)
Return type
[`Bitrix24\SDK\Services\Placement\Result\RegisterUserTypeResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/UserFieldType.php#L116-L126)
Return type
[`Bitrix24\SDK\Services\Placement\Result\DeleteUserTypeResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/Placement.php#L33-L48)
Return type
[`Bitrix24\SDK\Services\Placement\Result\PlacementBindResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/Placement.php#L63-L74)
Return type
[`Bitrix24\SDK\Services\Placement\Result\PlacementUnbindResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/Placement.php#L89-L96)
Return type
[`Bitrix24\SDK\Services\Placement\Result\PlacementLocationCodesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/Placement.php#L110-L113)
Return type
[`Bitrix24\SDK\Services\Placement\Result\PlacementsLocationInformationResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Services/Placement/Result/PlacementsLocationInformationResult.php)| \ No newline at end of file +|`–`|[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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L44-L47)
Return type
[`Bitrix24\SDK\Services\Main\Result\ServerTimeResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L61-L64)
Return type
[`Bitrix24\SDK\Services\Main\Result\UserProfileResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L79-L84)
Return type
[`Bitrix24\SDK\Core\Response\Response`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L99-L104)
Return type
[`Bitrix24\SDK\Core\Response\Response`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L119-L126)
Return type
[`Bitrix24\SDK\Services\Main\Result\MethodAffordabilityResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L157-L160)
Return type
[`Bitrix24\SDK\Core\Response\Response`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L212-L215)
Return type
[`Bitrix24\SDK\Core\Response\Response`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L229-L232)
Return type
[`Bitrix24\SDK\Services\Main\Result\ApplicationInfoResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L246-L249)
Return type
[`Bitrix24\SDK\Services\Main\Result\IsUserAdminResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Catalog/Service/Catalog.php#L81-L84)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Product/Service/Product.php#L92-L95)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Product/Service/Product.php#L131-L142)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Userfield/Service/Userfield.php#L77-L80)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategory.php#L55-L65)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategory.php#L83-L93)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategory.php#L109-L112)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategory.php#L150-L153)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategory.php#L269-L280)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/Deal.php#L105-L116)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/Deal.php#L134-L144)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/Deal.php#L277-L289)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealProductRows.php#L108-L119)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealUserfield.php#L139-L159)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealUserfield.php#L177-L187)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealUserfield.php#L232-L243)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealContact.php#L49-L64)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealContact.php#L78-L81)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealContact.php#L127-L137)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealContact.php#L160-L171)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealContact.php#L190-L203)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/Contact.php#L117-L128)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/Contact.php#L146-L156)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/Contact.php#L172-L175)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/Contact.php#L401-L413)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/ContactUserfield.php#L137-L157)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/ContactUserfield.php#L175-L185)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/ContactUserfield.php#L230-L241)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L110-L120)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L138-L148)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L164-L167)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L382-L393)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Product/Service/Product.php#L87-L97)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Product/Service/Product.php#L115-L125)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Product/Service/Product.php#L162-L165)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Product/Service/Product.php#L240-L251)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Lead/Service/Lead.php#L124-L135)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Lead/Service/Lead.php#L153-L163)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Lead/Service/Lead.php#L179-L182)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Lead/Service/Lead.php#L316-L328)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Item/Service/Item.php#L88-L95)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Item/Service/Item.php#L112-L115)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Item/Service/Item.php#L177-L189)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Activity/Service/Activity.php#L147-L153)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Template/Service/Template.php#L57-L72)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Template/Service/Template.php#L92-L127)
Return type
[``](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/)| +|`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/feature/390-prepare-publish-2-0/src/Services/Workflows/Template/Service/Template.php#L145-L150)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Robot/Service/Robot.php#L110-L116)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/User/Service/User.php#L43-L46)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/User/Service/User.php#L59-L62)
Return type
[`Bitrix24\SDK\Services\User\Result\UserResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/User/Service/User.php#L77-L92)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/User/Service/User.php#L104-L116)
Return type
[`Bitrix24\SDK\Services\User\Result\UsersResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/User/Service/User.php#L129-L137)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/User/Service/User.php#L151-L154)
Return type
[`Bitrix24\SDK\Services\User\Result\UsersResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/ExternalCall/Service/ExternalCall.php#L324-L331)
Return type
[`Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/ExternalCall/Service/ExternalCall.php#L347-L354)
Return type
[`Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/ExternalLine/Service/ExternalLine.php#L76-L81)
Return type
[`Bitrix24\SDK\Core\Result\EmptyResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IM/Notify/Service/Notify.php#L44-L64)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IM/Notify/Service/Notify.php#L71-L91)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IM/Notify/Service/Notify.php#L98-L112)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IM/Notify/Service/Notify.php#L156-L167)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IM/Notify/Service/Notify.php#L174-L186)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IM/Notify/Service/Notify.php#L193-L205)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/UserConsent/Service/UserConsent.php#L40-L43)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/UserConsent/Service/UserConsentAgreement.php#L39-L42)
Return type
[`Bitrix24\SDK\Services\UserConsent\Result\UserConsentAgreementsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/UserConsent/Service/UserConsentAgreement.php#L54-L70)
Return type
[`Bitrix24\SDK\Services\UserConsent\Result\UserConsentAgreementTextResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IMOpenLines/Service/Network.php#L38-L48)
Return type
[`Bitrix24\SDK\Services\IMOpenLines\Result\JoinOpenLineResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IMOpenLines/Service/Network.php#L58-L80)
Return type
[`Bitrix24\SDK\Services\IMOpenLines\Result\AddedMessageItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Event.php#L46-L54)
Return type
[`Bitrix24\SDK\Services\Main\Result\EventListResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Event.php#L69-L85)
Return type
[`Bitrix24\SDK\Services\Main\Result\EventHandlerBindResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Event.php#L100-L112)
Return type
[`Bitrix24\SDK\Services\Main\Result\EventHandlerUnbindResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Event.php#L125-L128)
Return type
[`Bitrix24\SDK\Core\Response\Response`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Event.php#L142-L145)
Return type
[`Bitrix24\SDK\Services\Main\Result\EventHandlersResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/UserFieldType.php#L45-L58)
Return type
[`Bitrix24\SDK\Services\Placement\Result\RegisterUserTypeResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/UserFieldType.php#L72-L77)
Return type
[`Bitrix24\SDK\Services\Placement\Result\UserFieldTypesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/UserFieldType.php#L96-L109)
Return type
[`Bitrix24\SDK\Services\Placement\Result\RegisterUserTypeResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/UserFieldType.php#L125-L135)
Return type
[`Bitrix24\SDK\Services\Placement\Result\DeleteUserTypeResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/Placement.php#L42-L54)
Return type
[`Bitrix24\SDK\Services\Placement\Result\PlacementBindResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/Placement.php#L68-L79)
Return type
[`Bitrix24\SDK\Services\Placement\Result\PlacementUnbindResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/Placement.php#L93-L100)
Return type
[`Bitrix24\SDK\Services\Placement\Result\PlacementLocationCodesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/Placement.php#L114-L117)
Return type
[`Bitrix24\SDK\Services\Placement\Result\PlacementsLocationInformationResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Services/Placement/Result/PlacementsLocationInformationResult.php)| \ No newline at end of file diff --git a/examples/local-application/index.php b/examples/local-application/index.php index 64573a63..a5f7fe27 100644 --- a/examples/local-application/index.php +++ b/examples/local-application/index.php @@ -1,4 +1,14 @@ + * + * For 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; diff --git a/examples/local-application/install.php b/examples/local-application/install.php index f5812ca7..93388018 100644 --- a/examples/local-application/install.php +++ b/examples/local-application/install.php @@ -1,4 +1,14 @@ + * + * For the full copyright and license information, please view the MIT-LICENSE.txt + * file that was distributed with this source code. + */ + declare(strict_types=1); ?>
diff --git a/examples/webhook/example.php b/examples/webhook/example.php
index 72a5b825..446fb703 100644
--- a/examples/webhook/example.php
+++ b/examples/webhook/example.php
@@ -1,4 +1,14 @@
 
+ *
+ * For 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;
diff --git a/rector.php b/rector.php
index 92873a08..a7f6568e 100644
--- a/rector.php
+++ b/rector.php
@@ -1,5 +1,14 @@
 
+ *
+ * For 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;
diff --git a/src/Application/ApplicationStatus.php b/src/Application/ApplicationStatus.php
index a6cc86a1..d5cdbbaa 100644
--- a/src/Application/ApplicationStatus.php
+++ b/src/Application/ApplicationStatus.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterface.php b/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterface.php
index 4e89f926..2113d6da 100644
--- a/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterface.php
+++ b/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterface.php
@@ -1,5 +1,15 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationStatus.php b/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationStatus.php
index 66f6d43f..985e0927 100644
--- a/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationStatus.php
+++ b/src/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationStatus.php
@@ -1,5 +1,15 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationApplicationStatusChangedEvent.php b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationApplicationStatusChangedEvent.php
index 8da8046f..19f00de5 100644
--- a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationApplicationStatusChangedEvent.php
+++ b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationApplicationStatusChangedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationBitrix24PartnerChangedEvent.php b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationBitrix24PartnerChangedEvent.php
index b86d95d8..1b5fdaa3 100644
--- a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationBitrix24PartnerChangedEvent.php
+++ b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationBitrix24PartnerChangedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationBitrix24PartnerContactPersonChangedEvent.php b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationBitrix24PartnerContactPersonChangedEvent.php
index 7d6e8898..1569a932 100644
--- a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationBitrix24PartnerContactPersonChangedEvent.php
+++ b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationBitrix24PartnerContactPersonChangedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationBlockedEvent.php b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationBlockedEvent.php
index 36ecd6fe..c0df86e9 100644
--- a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationBlockedEvent.php
+++ b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationBlockedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationContactPersonChangedEvent.php b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationContactPersonChangedEvent.php
index c4ba7c18..1b3b7861 100644
--- a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationContactPersonChangedEvent.php
+++ b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationContactPersonChangedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationCreatedEvent.php b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationCreatedEvent.php
index 39e81e5e..b3498a2c 100644
--- a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationCreatedEvent.php
+++ b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationCreatedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationExternalIdChangedEvent.php b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationExternalIdChangedEvent.php
index a3db2852..68faf3c5 100644
--- a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationExternalIdChangedEvent.php
+++ b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationExternalIdChangedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationFinishedEvent.php b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationFinishedEvent.php
index 7cb872a7..191d99be 100644
--- a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationFinishedEvent.php
+++ b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationFinishedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationPortalLicenseFamilyChangedEvent.php b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationPortalLicenseFamilyChangedEvent.php
index ec203e88..18931dd3 100644
--- a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationPortalLicenseFamilyChangedEvent.php
+++ b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationPortalLicenseFamilyChangedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationPortalUsersCountChangedEvent.php b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationPortalUsersCountChangedEvent.php
index 9ba74712..bdb6695e 100644
--- a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationPortalUsersCountChangedEvent.php
+++ b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationPortalUsersCountChangedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationUnblockedEvent.php b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationUnblockedEvent.php
index a473b030..91788c03 100644
--- a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationUnblockedEvent.php
+++ b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationUnblockedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationUninstalledEvent.php b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationUninstalledEvent.php
index bc100a67..06256df8 100644
--- a/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationUninstalledEvent.php
+++ b/src/Application/Contracts/ApplicationInstallations/Events/ApplicationInstallationUninstalledEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ApplicationInstallations/Exceptions/ApplicationInstallationNotFoundException.php b/src/Application/Contracts/ApplicationInstallations/Exceptions/ApplicationInstallationNotFoundException.php
index 99e3b6a0..a25bce8e 100644
--- a/src/Application/Contracts/ApplicationInstallations/Exceptions/ApplicationInstallationNotFoundException.php
+++ b/src/Application/Contracts/ApplicationInstallations/Exceptions/ApplicationInstallationNotFoundException.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ApplicationInstallations/Repository/ApplicationInstallationRepositoryInterface.php b/src/Application/Contracts/ApplicationInstallations/Repository/ApplicationInstallationRepositoryInterface.php
index d08160e7..51e9c786 100644
--- a/src/Application/Contracts/ApplicationInstallations/Repository/ApplicationInstallationRepositoryInterface.php
+++ b/src/Application/Contracts/ApplicationInstallations/Repository/ApplicationInstallationRepositoryInterface.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterface.php b/src/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterface.php
index cf6a9b4e..9a978e79 100644
--- a/src/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterface.php
+++ b/src/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterface.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountStatus.php b/src/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountStatus.php
index 97f16cb5..52c871d1 100644
--- a/src/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountStatus.php
+++ b/src/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountStatus.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountApplicationInstalledEvent.php b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountApplicationInstalledEvent.php
index f3fabff9..67c03e01 100644
--- a/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountApplicationInstalledEvent.php
+++ b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountApplicationInstalledEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountApplicationUninstalledEvent.php b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountApplicationUninstalledEvent.php
index 6aa4fa9f..2928b59b 100644
--- a/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountApplicationUninstalledEvent.php
+++ b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountApplicationUninstalledEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountApplicationVersionUpdatedEvent.php b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountApplicationVersionUpdatedEvent.php
index c2a2d4f8..fe98e4a4 100644
--- a/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountApplicationVersionUpdatedEvent.php
+++ b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountApplicationVersionUpdatedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountBlockedEvent.php b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountBlockedEvent.php
index c80c6a38..4a397dc6 100644
--- a/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountBlockedEvent.php
+++ b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountBlockedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountCreatedEvent.php b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountCreatedEvent.php
index be4079a9..8458ecce 100644
--- a/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountCreatedEvent.php
+++ b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountCreatedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountDeletedEvent.php b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountDeletedEvent.php
index ab5bbb98..a2ab5139 100644
--- a/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountDeletedEvent.php
+++ b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountDeletedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountDomainUrlChangedEvent.php b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountDomainUrlChangedEvent.php
index ebd52953..2be28c02 100644
--- a/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountDomainUrlChangedEvent.php
+++ b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountDomainUrlChangedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountUnblockedEvent.php b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountUnblockedEvent.php
index 8915f472..3227745e 100644
--- a/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountUnblockedEvent.php
+++ b/src/Application/Contracts/Bitrix24Accounts/Events/Bitrix24AccountUnblockedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Bitrix24Accounts/Exceptions/Bitrix24AccountNotFoundException.php b/src/Application/Contracts/Bitrix24Accounts/Exceptions/Bitrix24AccountNotFoundException.php
index c785f261..9ff84446 100644
--- a/src/Application/Contracts/Bitrix24Accounts/Exceptions/Bitrix24AccountNotFoundException.php
+++ b/src/Application/Contracts/Bitrix24Accounts/Exceptions/Bitrix24AccountNotFoundException.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterface.php b/src/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterface.php
index e0d01d56..50d48fa8 100644
--- a/src/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterface.php
+++ b/src/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterface.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterface.php b/src/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterface.php
index cb652fe6..21f90883 100644
--- a/src/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterface.php
+++ b/src/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterface.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerStatus.php b/src/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerStatus.php
index f7126467..0071a2d7 100644
--- a/src/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerStatus.php
+++ b/src/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerStatus.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerBlockedEvent.php b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerBlockedEvent.php
index e19607fd..ce1e7495 100644
--- a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerBlockedEvent.php
+++ b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerBlockedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerCreatedEvent.php b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerCreatedEvent.php
index 9f1e234b..60752b94 100644
--- a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerCreatedEvent.php
+++ b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerCreatedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerDeletedEvent.php b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerDeletedEvent.php
index 3052f5a8..ead49c4e 100644
--- a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerDeletedEvent.php
+++ b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerDeletedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerEmailChangedEvent.php b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerEmailChangedEvent.php
index 411de5ae..c9d76fb2 100644
--- a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerEmailChangedEvent.php
+++ b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerEmailChangedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerExternalIdChangedEvent.php b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerExternalIdChangedEvent.php
index 3f0355af..295d7ba2 100644
--- a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerExternalIdChangedEvent.php
+++ b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerExternalIdChangedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerOpenLineIdChangedEvent.php b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerOpenLineIdChangedEvent.php
index a782312a..a6c7d916 100644
--- a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerOpenLineIdChangedEvent.php
+++ b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerOpenLineIdChangedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerPartnerIdChangedEvent.php b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerPartnerIdChangedEvent.php
index 6b85cfc1..697282e7 100644
--- a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerPartnerIdChangedEvent.php
+++ b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerPartnerIdChangedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerPhoneChangedEvent.php b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerPhoneChangedEvent.php
index dcf26f55..97948095 100644
--- a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerPhoneChangedEvent.php
+++ b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerPhoneChangedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerSiteChangedEvent.php b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerSiteChangedEvent.php
index eb6e29ff..7477c907 100644
--- a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerSiteChangedEvent.php
+++ b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerSiteChangedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerTitleChangedEvent.php b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerTitleChangedEvent.php
index 48d87a76..50cae9dd 100644
--- a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerTitleChangedEvent.php
+++ b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerTitleChangedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerUnblockedEvent.php b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerUnblockedEvent.php
index 084d6a7b..84d01860 100644
--- a/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerUnblockedEvent.php
+++ b/src/Application/Contracts/Bitrix24Partners/Events/Bitrix24PartnerUnblockedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Bitrix24Partners/Exceptions/Bitrix24PartnerNotFoundException.php b/src/Application/Contracts/Bitrix24Partners/Exceptions/Bitrix24PartnerNotFoundException.php
index 682d5753..47bee12a 100644
--- a/src/Application/Contracts/Bitrix24Partners/Exceptions/Bitrix24PartnerNotFoundException.php
+++ b/src/Application/Contracts/Bitrix24Partners/Exceptions/Bitrix24PartnerNotFoundException.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Bitrix24Partners/Repository/Bitrix24PartnerRepositoryInterface.php b/src/Application/Contracts/Bitrix24Partners/Repository/Bitrix24PartnerRepositoryInterface.php
index 7b9a7ea3..7b78fbbb 100644
--- a/src/Application/Contracts/Bitrix24Partners/Repository/Bitrix24PartnerRepositoryInterface.php
+++ b/src/Application/Contracts/Bitrix24Partners/Repository/Bitrix24PartnerRepositoryInterface.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ContactPersons/Entity/ContactPersonInterface.php b/src/Application/Contracts/ContactPersons/Entity/ContactPersonInterface.php
index a2a7c7c3..384c97f8 100644
--- a/src/Application/Contracts/ContactPersons/Entity/ContactPersonInterface.php
+++ b/src/Application/Contracts/ContactPersons/Entity/ContactPersonInterface.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ContactPersons/Entity/ContactPersonStatus.php b/src/Application/Contracts/ContactPersons/Entity/ContactPersonStatus.php
index f437a292..25ebd80b 100644
--- a/src/Application/Contracts/ContactPersons/Entity/ContactPersonStatus.php
+++ b/src/Application/Contracts/ContactPersons/Entity/ContactPersonStatus.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ContactPersons/Entity/FullName.php b/src/Application/Contracts/ContactPersons/Entity/FullName.php
index 18892be2..e1e3c6b4 100644
--- a/src/Application/Contracts/ContactPersons/Entity/FullName.php
+++ b/src/Application/Contracts/ContactPersons/Entity/FullName.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ContactPersons/Events/ContactPersonBlockedEvent.php b/src/Application/Contracts/ContactPersons/Events/ContactPersonBlockedEvent.php
index 43ca80ef..ec909b0a 100644
--- a/src/Application/Contracts/ContactPersons/Events/ContactPersonBlockedEvent.php
+++ b/src/Application/Contracts/ContactPersons/Events/ContactPersonBlockedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ContactPersons/Events/ContactPersonCreatedEvent.php b/src/Application/Contracts/ContactPersons/Events/ContactPersonCreatedEvent.php
index 5c1e5ff2..f1735cfb 100644
--- a/src/Application/Contracts/ContactPersons/Events/ContactPersonCreatedEvent.php
+++ b/src/Application/Contracts/ContactPersons/Events/ContactPersonCreatedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ContactPersons/Events/ContactPersonDeletedEvent.php b/src/Application/Contracts/ContactPersons/Events/ContactPersonDeletedEvent.php
index 1fceaeef..473ac0c4 100644
--- a/src/Application/Contracts/ContactPersons/Events/ContactPersonDeletedEvent.php
+++ b/src/Application/Contracts/ContactPersons/Events/ContactPersonDeletedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ContactPersons/Events/ContactPersonEmailChangedEvent.php b/src/Application/Contracts/ContactPersons/Events/ContactPersonEmailChangedEvent.php
index a8c008e2..49e4688e 100644
--- a/src/Application/Contracts/ContactPersons/Events/ContactPersonEmailChangedEvent.php
+++ b/src/Application/Contracts/ContactPersons/Events/ContactPersonEmailChangedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ContactPersons/Events/ContactPersonEmailVerifiedEvent.php b/src/Application/Contracts/ContactPersons/Events/ContactPersonEmailVerifiedEvent.php
index 3158378d..081bdafc 100644
--- a/src/Application/Contracts/ContactPersons/Events/ContactPersonEmailVerifiedEvent.php
+++ b/src/Application/Contracts/ContactPersons/Events/ContactPersonEmailVerifiedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ContactPersons/Events/ContactPersonFullNameChangedEvent.php b/src/Application/Contracts/ContactPersons/Events/ContactPersonFullNameChangedEvent.php
index 78a86705..8f75e03f 100644
--- a/src/Application/Contracts/ContactPersons/Events/ContactPersonFullNameChangedEvent.php
+++ b/src/Application/Contracts/ContactPersons/Events/ContactPersonFullNameChangedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ContactPersons/Events/ContactPersonLinkedToExternalEntityEvent.php b/src/Application/Contracts/ContactPersons/Events/ContactPersonLinkedToExternalEntityEvent.php
index fb01330a..cc4c8b86 100644
--- a/src/Application/Contracts/ContactPersons/Events/ContactPersonLinkedToExternalEntityEvent.php
+++ b/src/Application/Contracts/ContactPersons/Events/ContactPersonLinkedToExternalEntityEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ContactPersons/Events/ContactPersonMobilePhoneChangedEvent.php b/src/Application/Contracts/ContactPersons/Events/ContactPersonMobilePhoneChangedEvent.php
index c67da565..af5594a8 100644
--- a/src/Application/Contracts/ContactPersons/Events/ContactPersonMobilePhoneChangedEvent.php
+++ b/src/Application/Contracts/ContactPersons/Events/ContactPersonMobilePhoneChangedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ContactPersons/Events/ContactPersonMobilePhoneVerifiedEvent.php b/src/Application/Contracts/ContactPersons/Events/ContactPersonMobilePhoneVerifiedEvent.php
index 47f73e1a..2a990d69 100644
--- a/src/Application/Contracts/ContactPersons/Events/ContactPersonMobilePhoneVerifiedEvent.php
+++ b/src/Application/Contracts/ContactPersons/Events/ContactPersonMobilePhoneVerifiedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ContactPersons/Events/ContactPersonUnblockedEvent.php b/src/Application/Contracts/ContactPersons/Events/ContactPersonUnblockedEvent.php
index 158bff3e..2f3b0e7b 100644
--- a/src/Application/Contracts/ContactPersons/Events/ContactPersonUnblockedEvent.php
+++ b/src/Application/Contracts/ContactPersons/Events/ContactPersonUnblockedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ContactPersons/Exceptions/ContactPersonNotFoundException.php b/src/Application/Contracts/ContactPersons/Exceptions/ContactPersonNotFoundException.php
index d6842524..94d9fc20 100644
--- a/src/Application/Contracts/ContactPersons/Exceptions/ContactPersonNotFoundException.php
+++ b/src/Application/Contracts/ContactPersons/Exceptions/ContactPersonNotFoundException.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterface.php b/src/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterface.php
index 0042e73e..880c7299 100644
--- a/src/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterface.php
+++ b/src/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterface.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Contracts/Events/AggregateRootEventsEmitterInterface.php b/src/Application/Contracts/Events/AggregateRootEventsEmitterInterface.php
index 5dbdbc45..15ee1d3b 100644
--- a/src/Application/Contracts/Events/AggregateRootEventsEmitterInterface.php
+++ b/src/Application/Contracts/Events/AggregateRootEventsEmitterInterface.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/PortalLicenseFamily.php b/src/Application/PortalLicenseFamily.php
index cd286022..718fa953 100644
--- a/src/Application/PortalLicenseFamily.php
+++ b/src/Application/PortalLicenseFamily.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Requests/AbstractRequest.php b/src/Application/Requests/AbstractRequest.php
index 1adcb543..e5d39aba 100644
--- a/src/Application/Requests/AbstractRequest.php
+++ b/src/Application/Requests/AbstractRequest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Requests/Events/AbstractEventRequest.php b/src/Application/Requests/Events/AbstractEventRequest.php
index ba207e3b..f2ea13c8 100644
--- a/src/Application/Requests/Events/AbstractEventRequest.php
+++ b/src/Application/Requests/Events/AbstractEventRequest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Requests/Events/EventAuthItem.php b/src/Application/Requests/Events/EventAuthItem.php
index f6b44103..57438567 100644
--- a/src/Application/Requests/Events/EventAuthItem.php
+++ b/src/Application/Requests/Events/EventAuthItem.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Requests/Events/EventInterface.php b/src/Application/Requests/Events/EventInterface.php
index 6358564e..c425937e 100644
--- a/src/Application/Requests/Events/EventInterface.php
+++ b/src/Application/Requests/Events/EventInterface.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Requests/Events/OnApplicationInstall/ApplicationData.php b/src/Application/Requests/Events/OnApplicationInstall/ApplicationData.php
index a63186a0..b60af89c 100644
--- a/src/Application/Requests/Events/OnApplicationInstall/ApplicationData.php
+++ b/src/Application/Requests/Events/OnApplicationInstall/ApplicationData.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Requests/Events/OnApplicationInstall/OnApplicationInstall.php b/src/Application/Requests/Events/OnApplicationInstall/OnApplicationInstall.php
index 64b9999d..283b5b47 100644
--- a/src/Application/Requests/Events/OnApplicationInstall/OnApplicationInstall.php
+++ b/src/Application/Requests/Events/OnApplicationInstall/OnApplicationInstall.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Requests/Events/OnApplicationUninstall/ApplicationData.php b/src/Application/Requests/Events/OnApplicationUninstall/ApplicationData.php
index bc49fb2e..72069390 100644
--- a/src/Application/Requests/Events/OnApplicationUninstall/ApplicationData.php
+++ b/src/Application/Requests/Events/OnApplicationUninstall/ApplicationData.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Requests/Events/OnApplicationUninstall/OnApplicationUninstall.php b/src/Application/Requests/Events/OnApplicationUninstall/OnApplicationUninstall.php
index a90450a1..96855e9e 100644
--- a/src/Application/Requests/Events/OnApplicationUninstall/OnApplicationUninstall.php
+++ b/src/Application/Requests/Events/OnApplicationUninstall/OnApplicationUninstall.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Application/Requests/Placement/PlacementRequest.php b/src/Application/Requests/Placement/PlacementRequest.php
index 9873ed46..0896fc0e 100644
--- a/src/Application/Requests/Placement/PlacementRequest.php
+++ b/src/Application/Requests/Placement/PlacementRequest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Attributes/ApiBatchMethodMetadata.php b/src/Attributes/ApiBatchMethodMetadata.php
index 50776ab9..08c765da 100644
--- a/src/Attributes/ApiBatchMethodMetadata.php
+++ b/src/Attributes/ApiBatchMethodMetadata.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Attributes/ApiBatchServiceMetadata.php b/src/Attributes/ApiBatchServiceMetadata.php
index f6d4a7fe..90b4bb47 100644
--- a/src/Attributes/ApiBatchServiceMetadata.php
+++ b/src/Attributes/ApiBatchServiceMetadata.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Attributes/ApiEndpointMetadata.php b/src/Attributes/ApiEndpointMetadata.php
index ebf74a83..d7d433b8 100644
--- a/src/Attributes/ApiEndpointMetadata.php
+++ b/src/Attributes/ApiEndpointMetadata.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Attributes/ApiServiceMetadata.php b/src/Attributes/ApiServiceMetadata.php
index 65bfbad9..1ca6a15b 100644
--- a/src/Attributes/ApiServiceMetadata.php
+++ b/src/Attributes/ApiServiceMetadata.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Attributes/Services/AttributesParser.php b/src/Attributes/Services/AttributesParser.php
index 8c1911fd..af8cb17c 100644
--- a/src/Attributes/Services/AttributesParser.php
+++ b/src/Attributes/Services/AttributesParser.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/ApiClient.php b/src/Core/ApiClient.php
index dc1f6b69..9f1df967 100644
--- a/src/Core/ApiClient.php
+++ b/src/Core/ApiClient.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/ApiLevelErrorHandler.php b/src/Core/ApiLevelErrorHandler.php
index 0417c1d5..e5fad9cb 100644
--- a/src/Core/ApiLevelErrorHandler.php
+++ b/src/Core/ApiLevelErrorHandler.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Batch.php b/src/Core/Batch.php
index acc6b378..8fd250a1 100644
--- a/src/Core/Batch.php
+++ b/src/Core/Batch.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/BulkItemsReader/BulkItemsReader.php b/src/Core/BulkItemsReader/BulkItemsReader.php
index fa6f7d7b..d91a1fff 100644
--- a/src/Core/BulkItemsReader/BulkItemsReader.php
+++ b/src/Core/BulkItemsReader/BulkItemsReader.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/BulkItemsReader/BulkItemsReaderBuilder.php b/src/Core/BulkItemsReader/BulkItemsReaderBuilder.php
index 84da8de9..449eaa42 100644
--- a/src/Core/BulkItemsReader/BulkItemsReaderBuilder.php
+++ b/src/Core/BulkItemsReader/BulkItemsReaderBuilder.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrder.php b/src/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrder.php
index cfe7f243..b0cf76da 100644
--- a/src/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrder.php
+++ b/src/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrder.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php b/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php
index b5a212f3..97a10e48 100644
--- a/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php
+++ b/src/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrder.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Commands/Command.php b/src/Core/Commands/Command.php
index 1a36caba..96139aa4 100644
--- a/src/Core/Commands/Command.php
+++ b/src/Core/Commands/Command.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Commands/CommandCollection.php b/src/Core/Commands/CommandCollection.php
index 01930847..17f2a7b9 100644
--- a/src/Core/Commands/CommandCollection.php
+++ b/src/Core/Commands/CommandCollection.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Contracts/AddedItemIdResultInterface.php b/src/Core/Contracts/AddedItemIdResultInterface.php
index 465bd43c..41808b4a 100644
--- a/src/Core/Contracts/AddedItemIdResultInterface.php
+++ b/src/Core/Contracts/AddedItemIdResultInterface.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Contracts/ApiClientInterface.php b/src/Core/Contracts/ApiClientInterface.php
index f1e52855..748bbfb6 100644
--- a/src/Core/Contracts/ApiClientInterface.php
+++ b/src/Core/Contracts/ApiClientInterface.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Contracts/BatchOperationsInterface.php b/src/Core/Contracts/BatchOperationsInterface.php
index e11c804b..e79b415c 100644
--- a/src/Core/Contracts/BatchOperationsInterface.php
+++ b/src/Core/Contracts/BatchOperationsInterface.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Contracts/BulkItemsReaderInterface.php b/src/Core/Contracts/BulkItemsReaderInterface.php
index 9c3ee383..c9d8145d 100644
--- a/src/Core/Contracts/BulkItemsReaderInterface.php
+++ b/src/Core/Contracts/BulkItemsReaderInterface.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Contracts/CoreInterface.php b/src/Core/Contracts/CoreInterface.php
index d58ccf33..d3d232d0 100644
--- a/src/Core/Contracts/CoreInterface.php
+++ b/src/Core/Contracts/CoreInterface.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Contracts/DeletedItemResultInterface.php b/src/Core/Contracts/DeletedItemResultInterface.php
index 053bf8c7..868f541e 100644
--- a/src/Core/Contracts/DeletedItemResultInterface.php
+++ b/src/Core/Contracts/DeletedItemResultInterface.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Contracts/UpdatedItemResultInterface.php b/src/Core/Contracts/UpdatedItemResultInterface.php
index 7e95eda2..7dc006c2 100644
--- a/src/Core/Contracts/UpdatedItemResultInterface.php
+++ b/src/Core/Contracts/UpdatedItemResultInterface.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Core.php b/src/Core/Core.php
index 169d1020..345b61e1 100644
--- a/src/Core/Core.php
+++ b/src/Core/Core.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/CoreBuilder.php b/src/Core/CoreBuilder.php
index 96572cc1..a83eeac1 100644
--- a/src/Core/CoreBuilder.php
+++ b/src/Core/CoreBuilder.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Credentials/ApplicationProfile.php b/src/Core/Credentials/ApplicationProfile.php
index dbad55ab..f8b0a39f 100644
--- a/src/Core/Credentials/ApplicationProfile.php
+++ b/src/Core/Credentials/ApplicationProfile.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Credentials/AuthToken.php b/src/Core/Credentials/AuthToken.php
index 9ea72d7d..407cb50e 100644
--- a/src/Core/Credentials/AuthToken.php
+++ b/src/Core/Credentials/AuthToken.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Credentials/Credentials.php b/src/Core/Credentials/Credentials.php
index 3398104a..5a17e3d2 100644
--- a/src/Core/Credentials/Credentials.php
+++ b/src/Core/Credentials/Credentials.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Credentials/Endpoints.php b/src/Core/Credentials/Endpoints.php
index 6429ed02..a5dcb86f 100644
--- a/src/Core/Credentials/Endpoints.php
+++ b/src/Core/Credentials/Endpoints.php
@@ -1,5 +1,14 @@
 
+ *
+ * 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;
diff --git a/src/Core/Credentials/Scope.php b/src/Core/Credentials/Scope.php
index ca7671e0..1fabfac8 100644
--- a/src/Core/Credentials/Scope.php
+++ b/src/Core/Credentials/Scope.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Credentials/WebhookUrl.php b/src/Core/Credentials/WebhookUrl.php
index 8d7a8769..f45d513e 100644
--- a/src/Core/Credentials/WebhookUrl.php
+++ b/src/Core/Credentials/WebhookUrl.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Exceptions/AuthForbiddenException.php b/src/Core/Exceptions/AuthForbiddenException.php
index 2d444876..77bdb342 100644
--- a/src/Core/Exceptions/AuthForbiddenException.php
+++ b/src/Core/Exceptions/AuthForbiddenException.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Exceptions/BaseException.php b/src/Core/Exceptions/BaseException.php
index bb5fe834..a0a94c2e 100644
--- a/src/Core/Exceptions/BaseException.php
+++ b/src/Core/Exceptions/BaseException.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Exceptions/FileNotFoundException.php b/src/Core/Exceptions/FileNotFoundException.php
index 315dd5a6..1f592d6e 100644
--- a/src/Core/Exceptions/FileNotFoundException.php
+++ b/src/Core/Exceptions/FileNotFoundException.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Exceptions/ImmutableResultViolationException.php b/src/Core/Exceptions/ImmutableResultViolationException.php
index 1765180c..78f43671 100644
--- a/src/Core/Exceptions/ImmutableResultViolationException.php
+++ b/src/Core/Exceptions/ImmutableResultViolationException.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Exceptions/InvalidArgumentException.php b/src/Core/Exceptions/InvalidArgumentException.php
index 84c810ce..d891da52 100644
--- a/src/Core/Exceptions/InvalidArgumentException.php
+++ b/src/Core/Exceptions/InvalidArgumentException.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Exceptions/MethodConfirmWaitingException.php b/src/Core/Exceptions/MethodConfirmWaitingException.php
index 94141e00..8018452a 100644
--- a/src/Core/Exceptions/MethodConfirmWaitingException.php
+++ b/src/Core/Exceptions/MethodConfirmWaitingException.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Exceptions/MethodNotFoundException.php b/src/Core/Exceptions/MethodNotFoundException.php
index 892684b2..858b0ed7 100644
--- a/src/Core/Exceptions/MethodNotFoundException.php
+++ b/src/Core/Exceptions/MethodNotFoundException.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Exceptions/OperationTimeLimitExceededException.php b/src/Core/Exceptions/OperationTimeLimitExceededException.php
index 6311730e..2a1ef6f8 100644
--- a/src/Core/Exceptions/OperationTimeLimitExceededException.php
+++ b/src/Core/Exceptions/OperationTimeLimitExceededException.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Exceptions/QueryLimitExceededException.php b/src/Core/Exceptions/QueryLimitExceededException.php
index 7bd280d5..9ba9b4c8 100644
--- a/src/Core/Exceptions/QueryLimitExceededException.php
+++ b/src/Core/Exceptions/QueryLimitExceededException.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Exceptions/TransportException.php b/src/Core/Exceptions/TransportException.php
index d5c02064..4701cbaa 100644
--- a/src/Core/Exceptions/TransportException.php
+++ b/src/Core/Exceptions/TransportException.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Exceptions/UnknownScopeCodeException.php b/src/Core/Exceptions/UnknownScopeCodeException.php
index bd2e0973..e6af1e15 100644
--- a/src/Core/Exceptions/UnknownScopeCodeException.php
+++ b/src/Core/Exceptions/UnknownScopeCodeException.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Exceptions/UserNotFoundOrIsNotActiveException.php b/src/Core/Exceptions/UserNotFoundOrIsNotActiveException.php
index fbaefb1b..567ddcbd 100644
--- a/src/Core/Exceptions/UserNotFoundOrIsNotActiveException.php
+++ b/src/Core/Exceptions/UserNotFoundOrIsNotActiveException.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Exceptions/WrongAuthTypeException.php b/src/Core/Exceptions/WrongAuthTypeException.php
index b0126397..72bad354 100644
--- a/src/Core/Exceptions/WrongAuthTypeException.php
+++ b/src/Core/Exceptions/WrongAuthTypeException.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Fields/FieldsFilter.php b/src/Core/Fields/FieldsFilter.php
index 3dc6ab50..be27dba5 100644
--- a/src/Core/Fields/FieldsFilter.php
+++ b/src/Core/Fields/FieldsFilter.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Response/DTO/Pagination.php b/src/Core/Response/DTO/Pagination.php
index 12a7d78e..8d158ea8 100644
--- a/src/Core/Response/DTO/Pagination.php
+++ b/src/Core/Response/DTO/Pagination.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Response/DTO/RenewedAuthToken.php b/src/Core/Response/DTO/RenewedAuthToken.php
index 88c6ce88..8b4ed1a6 100644
--- a/src/Core/Response/DTO/RenewedAuthToken.php
+++ b/src/Core/Response/DTO/RenewedAuthToken.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Response/DTO/ResponseData.php b/src/Core/Response/DTO/ResponseData.php
index 481defa0..cbcec359 100644
--- a/src/Core/Response/DTO/ResponseData.php
+++ b/src/Core/Response/DTO/ResponseData.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Response/DTO/Time.php b/src/Core/Response/DTO/Time.php
index c6a508ca..d87f3814 100644
--- a/src/Core/Response/DTO/Time.php
+++ b/src/Core/Response/DTO/Time.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Response/Response.php b/src/Core/Response/Response.php
index 13cb3ac1..1f0efb2c 100644
--- a/src/Core/Response/Response.php
+++ b/src/Core/Response/Response.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Result/AbstractItem.php b/src/Core/Result/AbstractItem.php
index 4d13d439..7daec5f3 100644
--- a/src/Core/Result/AbstractItem.php
+++ b/src/Core/Result/AbstractItem.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Result/AbstractResult.php b/src/Core/Result/AbstractResult.php
index b3fae786..a9c0171c 100644
--- a/src/Core/Result/AbstractResult.php
+++ b/src/Core/Result/AbstractResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Result/AddedItemBatchResult.php b/src/Core/Result/AddedItemBatchResult.php
index eb765e6f..0babf68b 100644
--- a/src/Core/Result/AddedItemBatchResult.php
+++ b/src/Core/Result/AddedItemBatchResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Result/AddedItemResult.php b/src/Core/Result/AddedItemResult.php
index 509d0e4d..73ae94fa 100644
--- a/src/Core/Result/AddedItemResult.php
+++ b/src/Core/Result/AddedItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Result/DeletedItemBatchResult.php b/src/Core/Result/DeletedItemBatchResult.php
index 1d06b6f6..6e17d9c6 100644
--- a/src/Core/Result/DeletedItemBatchResult.php
+++ b/src/Core/Result/DeletedItemBatchResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Result/DeletedItemResult.php b/src/Core/Result/DeletedItemResult.php
index 75f599a2..76a9d49d 100644
--- a/src/Core/Result/DeletedItemResult.php
+++ b/src/Core/Result/DeletedItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Result/EmptyResult.php b/src/Core/Result/EmptyResult.php
index faccdbec..7119a7cc 100644
--- a/src/Core/Result/EmptyResult.php
+++ b/src/Core/Result/EmptyResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Result/FieldsResult.php b/src/Core/Result/FieldsResult.php
index d1069c82..3b0799ea 100644
--- a/src/Core/Result/FieldsResult.php
+++ b/src/Core/Result/FieldsResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Result/UpdatedItemBatchResult.php b/src/Core/Result/UpdatedItemBatchResult.php
index 67250b73..7456934c 100644
--- a/src/Core/Result/UpdatedItemBatchResult.php
+++ b/src/Core/Result/UpdatedItemBatchResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Result/UpdatedItemResult.php b/src/Core/Result/UpdatedItemResult.php
index 0ebd4d07..9656dddc 100644
--- a/src/Core/Result/UpdatedItemResult.php
+++ b/src/Core/Result/UpdatedItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Core/Result/UserInterfaceDialogCallResult.php b/src/Core/Result/UserInterfaceDialogCallResult.php
index 35ca3f0d..a5a19c66 100644
--- a/src/Core/Result/UserInterfaceDialogCallResult.php
+++ b/src/Core/Result/UserInterfaceDialogCallResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Events/AuthTokenRenewedEvent.php b/src/Events/AuthTokenRenewedEvent.php
index b3cab82a..985b9ba7 100644
--- a/src/Events/AuthTokenRenewedEvent.php
+++ b/src/Events/AuthTokenRenewedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Events/PortalDomainUrlChangedEvent.php b/src/Events/PortalDomainUrlChangedEvent.php
index dc948537..928b85d8 100644
--- a/src/Events/PortalDomainUrlChangedEvent.php
+++ b/src/Events/PortalDomainUrlChangedEvent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Infrastructure/Console/Commands/GenerateCoverageDocumentationCommand.php b/src/Infrastructure/Console/Commands/GenerateCoverageDocumentationCommand.php
index b8d860ac..026be74e 100644
--- a/src/Infrastructure/Console/Commands/GenerateCoverageDocumentationCommand.php
+++ b/src/Infrastructure/Console/Commands/GenerateCoverageDocumentationCommand.php
@@ -1,4 +1,13 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Infrastructure/Filesystem/Base64Encoder.php b/src/Infrastructure/Filesystem/Base64Encoder.php
index a13387bb..efa46705 100644
--- a/src/Infrastructure/Filesystem/Base64Encoder.php
+++ b/src/Infrastructure/Filesystem/Base64Encoder.php
@@ -1,5 +1,14 @@
 
+ *
+ * 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;
diff --git a/src/Infrastructure/HttpClient/RequestId/DefaultRequestIdGenerator.php b/src/Infrastructure/HttpClient/RequestId/DefaultRequestIdGenerator.php
index 84defcd0..846df54a 100644
--- a/src/Infrastructure/HttpClient/RequestId/DefaultRequestIdGenerator.php
+++ b/src/Infrastructure/HttpClient/RequestId/DefaultRequestIdGenerator.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Infrastructure/HttpClient/RequestId/RequestIdGeneratorInterface.php b/src/Infrastructure/HttpClient/RequestId/RequestIdGeneratorInterface.php
index 77ba06b2..acddc679 100644
--- a/src/Infrastructure/HttpClient/RequestId/RequestIdGeneratorInterface.php
+++ b/src/Infrastructure/HttpClient/RequestId/RequestIdGeneratorInterface.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser.php b/src/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser.php
index 093f2a62..51fd9c4c 100644
--- a/src/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser.php
+++ b/src/Infrastructure/HttpClient/TransportLayer/NetworkTimingsParser.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Infrastructure/HttpClient/TransportLayer/ResponseInfoParser.php b/src/Infrastructure/HttpClient/TransportLayer/ResponseInfoParser.php
index 386ba8e9..328af11d 100644
--- a/src/Infrastructure/HttpClient/TransportLayer/ResponseInfoParser.php
+++ b/src/Infrastructure/HttpClient/TransportLayer/ResponseInfoParser.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/src/Services/AbstractBatchService.php b/src/Services/AbstractBatchService.php
index c62a6b69..f4eafe95 100644
--- a/src/Services/AbstractBatchService.php
+++ b/src/Services/AbstractBatchService.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 declare(strict_types=1);
 
 namespace Bitrix24\SDK\Services;
diff --git a/src/Services/AbstractService.php b/src/Services/AbstractService.php
index a2ee2cfa..9d71d95c 100644
--- a/src/Services/AbstractService.php
+++ b/src/Services/AbstractService.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 declare(strict_types=1);
 
 namespace Bitrix24\SDK\Services;
diff --git a/src/Services/AbstractServiceBuilder.php b/src/Services/AbstractServiceBuilder.php
index 36c97565..33edbf89 100644
--- a/src/Services/AbstractServiceBuilder.php
+++ b/src/Services/AbstractServiceBuilder.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 declare(strict_types=1);
 
 namespace Bitrix24\SDK\Services;
diff --git a/src/Services/CRM/Activity/ActivityContentType.php b/src/Services/CRM/Activity/ActivityContentType.php
index 9c2137fe..57273409 100644
--- a/src/Services/CRM/Activity/ActivityContentType.php
+++ b/src/Services/CRM/Activity/ActivityContentType.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Activity/ActivityDirectionType.php b/src/Services/CRM/Activity/ActivityDirectionType.php
index c997419c..94b893b8 100644
--- a/src/Services/CRM/Activity/ActivityDirectionType.php
+++ b/src/Services/CRM/Activity/ActivityDirectionType.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Activity/ActivityFetcherBuilder.php b/src/Services/CRM/Activity/ActivityFetcherBuilder.php
index e4508320..f21ab419 100644
--- a/src/Services/CRM/Activity/ActivityFetcherBuilder.php
+++ b/src/Services/CRM/Activity/ActivityFetcherBuilder.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Activity/ActivityNotifyType.php b/src/Services/CRM/Activity/ActivityNotifyType.php
index 53927375..6ecbd718 100644
--- a/src/Services/CRM/Activity/ActivityNotifyType.php
+++ b/src/Services/CRM/Activity/ActivityNotifyType.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Activity/ActivityPriority.php b/src/Services/CRM/Activity/ActivityPriority.php
index cab170b1..dec4d9de 100644
--- a/src/Services/CRM/Activity/ActivityPriority.php
+++ b/src/Services/CRM/Activity/ActivityPriority.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Activity/ActivityStatus.php b/src/Services/CRM/Activity/ActivityStatus.php
index 9888a208..2678b8ca 100644
--- a/src/Services/CRM/Activity/ActivityStatus.php
+++ b/src/Services/CRM/Activity/ActivityStatus.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Activity/ActivityType.php b/src/Services/CRM/Activity/ActivityType.php
index ae42b7b5..46e96a59 100644
--- a/src/Services/CRM/Activity/ActivityType.php
+++ b/src/Services/CRM/Activity/ActivityType.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Activity/ReadModel/EmailFetcher.php b/src/Services/CRM/Activity/ReadModel/EmailFetcher.php
index 834ff449..0d535df5 100644
--- a/src/Services/CRM/Activity/ReadModel/EmailFetcher.php
+++ b/src/Services/CRM/Activity/ReadModel/EmailFetcher.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Activity/ReadModel/OpenLineFetcher.php b/src/Services/CRM/Activity/ReadModel/OpenLineFetcher.php
index bc753907..c371b266 100644
--- a/src/Services/CRM/Activity/ReadModel/OpenLineFetcher.php
+++ b/src/Services/CRM/Activity/ReadModel/OpenLineFetcher.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Activity/ReadModel/VoximplantFetcher.php b/src/Services/CRM/Activity/ReadModel/VoximplantFetcher.php
index 9143b2f9..9ffffa82 100644
--- a/src/Services/CRM/Activity/ReadModel/VoximplantFetcher.php
+++ b/src/Services/CRM/Activity/ReadModel/VoximplantFetcher.php
@@ -1,5 +1,13 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Activity/ReadModel/WebFormFetcher.php b/src/Services/CRM/Activity/ReadModel/WebFormFetcher.php
index 78e22715..b9b205be 100644
--- a/src/Services/CRM/Activity/ReadModel/WebFormFetcher.php
+++ b/src/Services/CRM/Activity/ReadModel/WebFormFetcher.php
@@ -1,5 +1,13 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Activity/Result/ActivitiesResult.php b/src/Services/CRM/Activity/Result/ActivitiesResult.php
index ce52ce3d..214f5271 100644
--- a/src/Services/CRM/Activity/Result/ActivitiesResult.php
+++ b/src/Services/CRM/Activity/Result/ActivitiesResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Activity/Result/ActivityItemResult.php b/src/Services/CRM/Activity/Result/ActivityItemResult.php
index 1e5768ba..8e819f40 100644
--- a/src/Services/CRM/Activity/Result/ActivityItemResult.php
+++ b/src/Services/CRM/Activity/Result/ActivityItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Activity/Result/ActivityResult.php b/src/Services/CRM/Activity/Result/ActivityResult.php
index 4b17e7ef..c15dcc3c 100644
--- a/src/Services/CRM/Activity/Result/ActivityResult.php
+++ b/src/Services/CRM/Activity/Result/ActivityResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Activity/Result/Email/EmailActivityItemResult.php b/src/Services/CRM/Activity/Result/Email/EmailActivityItemResult.php
index c3056932..77b9fc53 100644
--- a/src/Services/CRM/Activity/Result/Email/EmailActivityItemResult.php
+++ b/src/Services/CRM/Activity/Result/Email/EmailActivityItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Activity/Result/Email/EmailMeta.php b/src/Services/CRM/Activity/Result/Email/EmailMeta.php
index 939672b8..bb890e6e 100644
--- a/src/Services/CRM/Activity/Result/Email/EmailMeta.php
+++ b/src/Services/CRM/Activity/Result/Email/EmailMeta.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Activity/Result/Email/EmailSettings.php b/src/Services/CRM/Activity/Result/Email/EmailSettings.php
index 4562ec2b..8e3a1029 100644
--- a/src/Services/CRM/Activity/Result/Email/EmailSettings.php
+++ b/src/Services/CRM/Activity/Result/Email/EmailSettings.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Activity/Result/OpenLine/OpenLineActivityItemResult.php b/src/Services/CRM/Activity/Result/OpenLine/OpenLineActivityItemResult.php
index caa83230..5fec9612 100644
--- a/src/Services/CRM/Activity/Result/OpenLine/OpenLineActivityItemResult.php
+++ b/src/Services/CRM/Activity/Result/OpenLine/OpenLineActivityItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Activity/Result/OpenLine/OpenLineProviderParams.php b/src/Services/CRM/Activity/Result/OpenLine/OpenLineProviderParams.php
index 5920829f..8ca1c3f9 100644
--- a/src/Services/CRM/Activity/Result/OpenLine/OpenLineProviderParams.php
+++ b/src/Services/CRM/Activity/Result/OpenLine/OpenLineProviderParams.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Activity/Result/WebForm/VisitedPageItem.php b/src/Services/CRM/Activity/Result/WebForm/VisitedPageItem.php
index c479f8f7..16b20878 100644
--- a/src/Services/CRM/Activity/Result/WebForm/VisitedPageItem.php
+++ b/src/Services/CRM/Activity/Result/WebForm/VisitedPageItem.php
@@ -1,5 +1,13 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Activity/Result/WebForm/WebFormActivityItemResult.php b/src/Services/CRM/Activity/Result/WebForm/WebFormActivityItemResult.php
index e9b0742e..d36cc0df 100644
--- a/src/Services/CRM/Activity/Result/WebForm/WebFormActivityItemResult.php
+++ b/src/Services/CRM/Activity/Result/WebForm/WebFormActivityItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Activity/Result/WebForm/WebFormFieldItem.php b/src/Services/CRM/Activity/Result/WebForm/WebFormFieldItem.php
index 1fc1572e..715459d2 100644
--- a/src/Services/CRM/Activity/Result/WebForm/WebFormFieldItem.php
+++ b/src/Services/CRM/Activity/Result/WebForm/WebFormFieldItem.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Activity/Result/WebForm/WebFormMetadata.php b/src/Services/CRM/Activity/Result/WebForm/WebFormMetadata.php
index 29568019..c1a9c457 100644
--- a/src/Services/CRM/Activity/Result/WebForm/WebFormMetadata.php
+++ b/src/Services/CRM/Activity/Result/WebForm/WebFormMetadata.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Activity/Result/WebForm/WebFormProviderParams.php b/src/Services/CRM/Activity/Result/WebForm/WebFormProviderParams.php
index d61998a1..e8c8d572 100644
--- a/src/Services/CRM/Activity/Result/WebForm/WebFormProviderParams.php
+++ b/src/Services/CRM/Activity/Result/WebForm/WebFormProviderParams.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Activity/Service/Activity.php b/src/Services/CRM/Activity/Service/Activity.php
index 5c9b9605..6ef0993d 100644
--- a/src/Services/CRM/Activity/Service/Activity.php
+++ b/src/Services/CRM/Activity/Service/Activity.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Activity/Service/Batch.php b/src/Services/CRM/Activity/Service/Batch.php
index 57bce00a..06dba9b6 100644
--- a/src/Services/CRM/Activity/Service/Batch.php
+++ b/src/Services/CRM/Activity/Service/Batch.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/CRMServiceBuilder.php b/src/Services/CRM/CRMServiceBuilder.php
index 49678877..b3eb8964 100644
--- a/src/Services/CRM/CRMServiceBuilder.php
+++ b/src/Services/CRM/CRMServiceBuilder.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Common/Result/AbstractCrmItem.php b/src/Services/CRM/Common/Result/AbstractCrmItem.php
index c5cb8516..a2542cbf 100644
--- a/src/Services/CRM/Common/Result/AbstractCrmItem.php
+++ b/src/Services/CRM/Common/Result/AbstractCrmItem.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Common/Result/DiscountType.php b/src/Services/CRM/Common/Result/DiscountType.php
index fb380026..3b915fa0 100644
--- a/src/Services/CRM/Common/Result/DiscountType.php
+++ b/src/Services/CRM/Common/Result/DiscountType.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Common/Result/SystemFields/Types/Email.php b/src/Services/CRM/Common/Result/SystemFields/Types/Email.php
index 603cdae9..0dc80e13 100644
--- a/src/Services/CRM/Common/Result/SystemFields/Types/Email.php
+++ b/src/Services/CRM/Common/Result/SystemFields/Types/Email.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Common/Result/SystemFields/Types/EmailValueType.php b/src/Services/CRM/Common/Result/SystemFields/Types/EmailValueType.php
index 5f3bc5b2..083e3d0d 100644
--- a/src/Services/CRM/Common/Result/SystemFields/Types/EmailValueType.php
+++ b/src/Services/CRM/Common/Result/SystemFields/Types/EmailValueType.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Common/Result/SystemFields/Types/InstantMessenger.php b/src/Services/CRM/Common/Result/SystemFields/Types/InstantMessenger.php
index 35d92d0a..76fd1419 100644
--- a/src/Services/CRM/Common/Result/SystemFields/Types/InstantMessenger.php
+++ b/src/Services/CRM/Common/Result/SystemFields/Types/InstantMessenger.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Common/Result/SystemFields/Types/InstantMessengerValueType.php b/src/Services/CRM/Common/Result/SystemFields/Types/InstantMessengerValueType.php
index 87b5c223..43e57385 100644
--- a/src/Services/CRM/Common/Result/SystemFields/Types/InstantMessengerValueType.php
+++ b/src/Services/CRM/Common/Result/SystemFields/Types/InstantMessengerValueType.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Common/Result/SystemFields/Types/Phone.php b/src/Services/CRM/Common/Result/SystemFields/Types/Phone.php
index 73763cba..e981762d 100644
--- a/src/Services/CRM/Common/Result/SystemFields/Types/Phone.php
+++ b/src/Services/CRM/Common/Result/SystemFields/Types/Phone.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Common/Result/SystemFields/Types/PhoneValueType.php b/src/Services/CRM/Common/Result/SystemFields/Types/PhoneValueType.php
index 8d9636b4..04c010dc 100644
--- a/src/Services/CRM/Common/Result/SystemFields/Types/PhoneValueType.php
+++ b/src/Services/CRM/Common/Result/SystemFields/Types/PhoneValueType.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Common/Result/SystemFields/Types/Website.php b/src/Services/CRM/Common/Result/SystemFields/Types/Website.php
index e3a03600..bd533bba 100644
--- a/src/Services/CRM/Common/Result/SystemFields/Types/Website.php
+++ b/src/Services/CRM/Common/Result/SystemFields/Types/Website.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Common/Result/SystemFields/Types/WebsiteValueType.php b/src/Services/CRM/Common/Result/SystemFields/Types/WebsiteValueType.php
index dd9f322d..229b905b 100644
--- a/src/Services/CRM/Common/Result/SystemFields/Types/WebsiteValueType.php
+++ b/src/Services/CRM/Common/Result/SystemFields/Types/WebsiteValueType.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Contact/Result/ContactItemResult.php b/src/Services/CRM/Contact/Result/ContactItemResult.php
index 21744187..357de417 100644
--- a/src/Services/CRM/Contact/Result/ContactItemResult.php
+++ b/src/Services/CRM/Contact/Result/ContactItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Contact/Result/ContactResult.php b/src/Services/CRM/Contact/Result/ContactResult.php
index 4999cbdc..79a15253 100644
--- a/src/Services/CRM/Contact/Result/ContactResult.php
+++ b/src/Services/CRM/Contact/Result/ContactResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Contact/Result/ContactUserfieldItemResult.php b/src/Services/CRM/Contact/Result/ContactUserfieldItemResult.php
index 06058da6..310915e2 100644
--- a/src/Services/CRM/Contact/Result/ContactUserfieldItemResult.php
+++ b/src/Services/CRM/Contact/Result/ContactUserfieldItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Contact/Result/ContactUserfieldResult.php b/src/Services/CRM/Contact/Result/ContactUserfieldResult.php
index d1b50369..95f89f53 100644
--- a/src/Services/CRM/Contact/Result/ContactUserfieldResult.php
+++ b/src/Services/CRM/Contact/Result/ContactUserfieldResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Contact/Result/ContactUserfieldsResult.php b/src/Services/CRM/Contact/Result/ContactUserfieldsResult.php
index 30dbc44f..c5a1ff95 100644
--- a/src/Services/CRM/Contact/Result/ContactUserfieldsResult.php
+++ b/src/Services/CRM/Contact/Result/ContactUserfieldsResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Contact/Result/ContactsResult.php b/src/Services/CRM/Contact/Result/ContactsResult.php
index 82a0b2a4..120a2fc3 100644
--- a/src/Services/CRM/Contact/Result/ContactsResult.php
+++ b/src/Services/CRM/Contact/Result/ContactsResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Contact/Service/Batch.php b/src/Services/CRM/Contact/Service/Batch.php
index 58175335..9c280a92 100644
--- a/src/Services/CRM/Contact/Service/Batch.php
+++ b/src/Services/CRM/Contact/Service/Batch.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Contact/Service/Contact.php b/src/Services/CRM/Contact/Service/Contact.php
index 68e92ae0..2a74c331 100644
--- a/src/Services/CRM/Contact/Service/Contact.php
+++ b/src/Services/CRM/Contact/Service/Contact.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Contact/Service/ContactUserfield.php b/src/Services/CRM/Contact/Service/ContactUserfield.php
index 7a36c4cb..1b5a2639 100644
--- a/src/Services/CRM/Contact/Service/ContactUserfield.php
+++ b/src/Services/CRM/Contact/Service/ContactUserfield.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Deal/DealStageSemanticId.php b/src/Services/CRM/Deal/DealStageSemanticId.php
index e591b956..f0bf7850 100644
--- a/src/Services/CRM/Deal/DealStageSemanticId.php
+++ b/src/Services/CRM/Deal/DealStageSemanticId.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Deal/Result/DealCategoriesResult.php b/src/Services/CRM/Deal/Result/DealCategoriesResult.php
index 9d90c2bc..92667c28 100644
--- a/src/Services/CRM/Deal/Result/DealCategoriesResult.php
+++ b/src/Services/CRM/Deal/Result/DealCategoriesResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Deal/Result/DealCategoryItemResult.php b/src/Services/CRM/Deal/Result/DealCategoryItemResult.php
index fff65ecf..02f430da 100644
--- a/src/Services/CRM/Deal/Result/DealCategoryItemResult.php
+++ b/src/Services/CRM/Deal/Result/DealCategoryItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Deal/Result/DealCategoryResult.php b/src/Services/CRM/Deal/Result/DealCategoryResult.php
index 53d6867e..021f8420 100644
--- a/src/Services/CRM/Deal/Result/DealCategoryResult.php
+++ b/src/Services/CRM/Deal/Result/DealCategoryResult.php
@@ -1,5 +1,13 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Deal/Result/DealCategoryStageItemResult.php b/src/Services/CRM/Deal/Result/DealCategoryStageItemResult.php
index 50ca80ff..b8c198a6 100644
--- a/src/Services/CRM/Deal/Result/DealCategoryStageItemResult.php
+++ b/src/Services/CRM/Deal/Result/DealCategoryStageItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Deal/Result/DealCategoryStagesResult.php b/src/Services/CRM/Deal/Result/DealCategoryStagesResult.php
index c4f9ce82..0c421122 100644
--- a/src/Services/CRM/Deal/Result/DealCategoryStagesResult.php
+++ b/src/Services/CRM/Deal/Result/DealCategoryStagesResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Deal/Result/DealCategoryStatusResult.php b/src/Services/CRM/Deal/Result/DealCategoryStatusResult.php
index 4236ec4b..0f9166f5 100644
--- a/src/Services/CRM/Deal/Result/DealCategoryStatusResult.php
+++ b/src/Services/CRM/Deal/Result/DealCategoryStatusResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Deal/Result/DealContactItemResult.php b/src/Services/CRM/Deal/Result/DealContactItemResult.php
index 58a13ed6..010ddc11 100644
--- a/src/Services/CRM/Deal/Result/DealContactItemResult.php
+++ b/src/Services/CRM/Deal/Result/DealContactItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Deal/Result/DealContactItemsResult.php b/src/Services/CRM/Deal/Result/DealContactItemsResult.php
index 6f8a40c1..af24d8b1 100644
--- a/src/Services/CRM/Deal/Result/DealContactItemsResult.php
+++ b/src/Services/CRM/Deal/Result/DealContactItemsResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Deal/Result/DealItemResult.php b/src/Services/CRM/Deal/Result/DealItemResult.php
index 7deb3854..9cd56c1c 100644
--- a/src/Services/CRM/Deal/Result/DealItemResult.php
+++ b/src/Services/CRM/Deal/Result/DealItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Deal/Result/DealProductRowItemResult.php b/src/Services/CRM/Deal/Result/DealProductRowItemResult.php
index 886a9a98..2d97529e 100644
--- a/src/Services/CRM/Deal/Result/DealProductRowItemResult.php
+++ b/src/Services/CRM/Deal/Result/DealProductRowItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php b/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php
index 9cf683aa..f0b1a69f 100644
--- a/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php
+++ b/src/Services/CRM/Deal/Result/DealProductRowItemsResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Deal/Result/DealResult.php b/src/Services/CRM/Deal/Result/DealResult.php
index 4e9e01c3..d865b66d 100644
--- a/src/Services/CRM/Deal/Result/DealResult.php
+++ b/src/Services/CRM/Deal/Result/DealResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Deal/Result/DealSemanticStage.php b/src/Services/CRM/Deal/Result/DealSemanticStage.php
index 7fc7dde6..c913171c 100644
--- a/src/Services/CRM/Deal/Result/DealSemanticStage.php
+++ b/src/Services/CRM/Deal/Result/DealSemanticStage.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Deal/Result/DealUserfieldItemResult.php b/src/Services/CRM/Deal/Result/DealUserfieldItemResult.php
index 7531eae9..84642c84 100644
--- a/src/Services/CRM/Deal/Result/DealUserfieldItemResult.php
+++ b/src/Services/CRM/Deal/Result/DealUserfieldItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Deal/Result/DealUserfieldResult.php b/src/Services/CRM/Deal/Result/DealUserfieldResult.php
index 4358c882..9a75284d 100644
--- a/src/Services/CRM/Deal/Result/DealUserfieldResult.php
+++ b/src/Services/CRM/Deal/Result/DealUserfieldResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Deal/Result/DealUserfieldsResult.php b/src/Services/CRM/Deal/Result/DealUserfieldsResult.php
index 2aa60219..cc8c4701 100644
--- a/src/Services/CRM/Deal/Result/DealUserfieldsResult.php
+++ b/src/Services/CRM/Deal/Result/DealUserfieldsResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Deal/Result/DealsResult.php b/src/Services/CRM/Deal/Result/DealsResult.php
index 3fdaa070..22fbd428 100644
--- a/src/Services/CRM/Deal/Result/DealsResult.php
+++ b/src/Services/CRM/Deal/Result/DealsResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Deal/Service/Batch.php b/src/Services/CRM/Deal/Service/Batch.php
index 6a32e499..62bc9134 100644
--- a/src/Services/CRM/Deal/Service/Batch.php
+++ b/src/Services/CRM/Deal/Service/Batch.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Deal/Service/Deal.php b/src/Services/CRM/Deal/Service/Deal.php
index 12b07cd5..0f602bab 100644
--- a/src/Services/CRM/Deal/Service/Deal.php
+++ b/src/Services/CRM/Deal/Service/Deal.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Deal/Service/DealCategory.php b/src/Services/CRM/Deal/Service/DealCategory.php
index 9497bfe8..da8908ae 100644
--- a/src/Services/CRM/Deal/Service/DealCategory.php
+++ b/src/Services/CRM/Deal/Service/DealCategory.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Deal/Service/DealCategoryStage.php b/src/Services/CRM/Deal/Service/DealCategoryStage.php
index 6d608642..b9cb019c 100644
--- a/src/Services/CRM/Deal/Service/DealCategoryStage.php
+++ b/src/Services/CRM/Deal/Service/DealCategoryStage.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Deal/Service/DealContact.php b/src/Services/CRM/Deal/Service/DealContact.php
index 6f2ba9cd..0e5eb038 100644
--- a/src/Services/CRM/Deal/Service/DealContact.php
+++ b/src/Services/CRM/Deal/Service/DealContact.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Deal/Service/DealProductRows.php b/src/Services/CRM/Deal/Service/DealProductRows.php
index c9855202..ec6bf9ce 100644
--- a/src/Services/CRM/Deal/Service/DealProductRows.php
+++ b/src/Services/CRM/Deal/Service/DealProductRows.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Deal/Service/DealUserfield.php b/src/Services/CRM/Deal/Service/DealUserfield.php
index 74dc23ca..03080ba2 100644
--- a/src/Services/CRM/Deal/Service/DealUserfield.php
+++ b/src/Services/CRM/Deal/Service/DealUserfield.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Duplicates/Result/DuplicateResult.php b/src/Services/CRM/Duplicates/Result/DuplicateResult.php
index dffe44ad..3683f454 100644
--- a/src/Services/CRM/Duplicates/Result/DuplicateResult.php
+++ b/src/Services/CRM/Duplicates/Result/DuplicateResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Duplicates/Service/Duplicate.php b/src/Services/CRM/Duplicates/Service/Duplicate.php
index a3c4bfc6..aaf4ea87 100644
--- a/src/Services/CRM/Duplicates/Service/Duplicate.php
+++ b/src/Services/CRM/Duplicates/Service/Duplicate.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Duplicates/Service/EntityType.php b/src/Services/CRM/Duplicates/Service/EntityType.php
index 3e5583ea..a4165fa9 100644
--- a/src/Services/CRM/Duplicates/Service/EntityType.php
+++ b/src/Services/CRM/Duplicates/Service/EntityType.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Item/Result/ItemItemResult.php b/src/Services/CRM/Item/Result/ItemItemResult.php
index e67f5b10..5ac66a75 100644
--- a/src/Services/CRM/Item/Result/ItemItemResult.php
+++ b/src/Services/CRM/Item/Result/ItemItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Item/Result/ItemResult.php b/src/Services/CRM/Item/Result/ItemResult.php
index 1e6f36ad..d89251cd 100644
--- a/src/Services/CRM/Item/Result/ItemResult.php
+++ b/src/Services/CRM/Item/Result/ItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Item/Result/ItemsResult.php b/src/Services/CRM/Item/Result/ItemsResult.php
index 978ffc0d..9943e0b0 100644
--- a/src/Services/CRM/Item/Result/ItemsResult.php
+++ b/src/Services/CRM/Item/Result/ItemsResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Item/Service/Batch.php b/src/Services/CRM/Item/Service/Batch.php
index 25bcc5c8..546765ab 100644
--- a/src/Services/CRM/Item/Service/Batch.php
+++ b/src/Services/CRM/Item/Service/Batch.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Item/Service/Item.php b/src/Services/CRM/Item/Service/Item.php
index f257c9e0..5425be81 100644
--- a/src/Services/CRM/Item/Service/Item.php
+++ b/src/Services/CRM/Item/Service/Item.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Lead/Result/LeadItemResult.php b/src/Services/CRM/Lead/Result/LeadItemResult.php
index 3b269e48..347ac45e 100644
--- a/src/Services/CRM/Lead/Result/LeadItemResult.php
+++ b/src/Services/CRM/Lead/Result/LeadItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Lead/Result/LeadResult.php b/src/Services/CRM/Lead/Result/LeadResult.php
index 5fbfcc91..7f4d0f86 100644
--- a/src/Services/CRM/Lead/Result/LeadResult.php
+++ b/src/Services/CRM/Lead/Result/LeadResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Lead/Result/LeadsResult.php b/src/Services/CRM/Lead/Result/LeadsResult.php
index 2a2ebef3..203a5b54 100644
--- a/src/Services/CRM/Lead/Result/LeadsResult.php
+++ b/src/Services/CRM/Lead/Result/LeadsResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Lead/Service/Batch.php b/src/Services/CRM/Lead/Service/Batch.php
index fab4ab81..7b6e546c 100644
--- a/src/Services/CRM/Lead/Service/Batch.php
+++ b/src/Services/CRM/Lead/Service/Batch.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Lead/Service/Lead.php b/src/Services/CRM/Lead/Service/Lead.php
index f2c67aa1..02d9716c 100644
--- a/src/Services/CRM/Lead/Service/Lead.php
+++ b/src/Services/CRM/Lead/Service/Lead.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Product/Result/ProductItemResult.php b/src/Services/CRM/Product/Result/ProductItemResult.php
index 9d81c9a1..657621a0 100644
--- a/src/Services/CRM/Product/Result/ProductItemResult.php
+++ b/src/Services/CRM/Product/Result/ProductItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Product/Result/ProductResult.php b/src/Services/CRM/Product/Result/ProductResult.php
index 07ba6828..5cd5457f 100644
--- a/src/Services/CRM/Product/Result/ProductResult.php
+++ b/src/Services/CRM/Product/Result/ProductResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Product/Result/ProductsResult.php b/src/Services/CRM/Product/Result/ProductsResult.php
index dd8caf80..da840990 100644
--- a/src/Services/CRM/Product/Result/ProductsResult.php
+++ b/src/Services/CRM/Product/Result/ProductsResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/CRM/Product/Service/Batch.php b/src/Services/CRM/Product/Service/Batch.php
index 16c0fdb6..c4f7ac88 100644
--- a/src/Services/CRM/Product/Service/Batch.php
+++ b/src/Services/CRM/Product/Service/Batch.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Product/Service/Product.php b/src/Services/CRM/Product/Service/Product.php
index ddfb92a3..bf027036 100644
--- a/src/Services/CRM/Product/Service/Product.php
+++ b/src/Services/CRM/Product/Service/Product.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Settings/Result/SettingsModeResult.php b/src/Services/CRM/Settings/Result/SettingsModeResult.php
index 25167743..cc8642d0 100644
--- a/src/Services/CRM/Settings/Result/SettingsModeResult.php
+++ b/src/Services/CRM/Settings/Result/SettingsModeResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Settings/Service/Settings.php b/src/Services/CRM/Settings/Service/Settings.php
index 7f164be3..a99a7e1d 100644
--- a/src/Services/CRM/Settings/Service/Settings.php
+++ b/src/Services/CRM/Settings/Service/Settings.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Userfield/Exceptions/UserfieldNameIsTooLongException.php b/src/Services/CRM/Userfield/Exceptions/UserfieldNameIsTooLongException.php
index 1c637c9e..13d2fc5a 100644
--- a/src/Services/CRM/Userfield/Exceptions/UserfieldNameIsTooLongException.php
+++ b/src/Services/CRM/Userfield/Exceptions/UserfieldNameIsTooLongException.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Userfield/Exceptions/UserfieldNotFoundException.php b/src/Services/CRM/Userfield/Exceptions/UserfieldNotFoundException.php
index eb551e77..6205306f 100644
--- a/src/Services/CRM/Userfield/Exceptions/UserfieldNotFoundException.php
+++ b/src/Services/CRM/Userfield/Exceptions/UserfieldNotFoundException.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Userfield/Result/AbstractUserfieldItemResult.php b/src/Services/CRM/Userfield/Result/AbstractUserfieldItemResult.php
index 7c876fde..44416332 100644
--- a/src/Services/CRM/Userfield/Result/AbstractUserfieldItemResult.php
+++ b/src/Services/CRM/Userfield/Result/AbstractUserfieldItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Userfield/Result/UserfieldTypeItemResult.php b/src/Services/CRM/Userfield/Result/UserfieldTypeItemResult.php
index 57df56f0..5e697627 100644
--- a/src/Services/CRM/Userfield/Result/UserfieldTypeItemResult.php
+++ b/src/Services/CRM/Userfield/Result/UserfieldTypeItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Userfield/Result/UserfieldTypesResult.php b/src/Services/CRM/Userfield/Result/UserfieldTypesResult.php
index 507caa83..2742b2f7 100644
--- a/src/Services/CRM/Userfield/Result/UserfieldTypesResult.php
+++ b/src/Services/CRM/Userfield/Result/UserfieldTypesResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/CRM/Userfield/Service/Userfield.php b/src/Services/CRM/Userfield/Service/Userfield.php
index 3caee0e8..e855723b 100644
--- a/src/Services/CRM/Userfield/Service/Userfield.php
+++ b/src/Services/CRM/Userfield/Service/Userfield.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Catalog/Catalog/Result/CatalogItemResult.php b/src/Services/Catalog/Catalog/Result/CatalogItemResult.php
index 7a406f88..e62fc7cb 100644
--- a/src/Services/Catalog/Catalog/Result/CatalogItemResult.php
+++ b/src/Services/Catalog/Catalog/Result/CatalogItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Catalog/Catalog/Result/CatalogResult.php b/src/Services/Catalog/Catalog/Result/CatalogResult.php
index f4e4adf6..aa468aa8 100644
--- a/src/Services/Catalog/Catalog/Result/CatalogResult.php
+++ b/src/Services/Catalog/Catalog/Result/CatalogResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Catalog/Catalog/Result/CatalogsResult.php b/src/Services/Catalog/Catalog/Result/CatalogsResult.php
index 44c9799d..add5f259 100644
--- a/src/Services/Catalog/Catalog/Result/CatalogsResult.php
+++ b/src/Services/Catalog/Catalog/Result/CatalogsResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Catalog/Catalog/Service/Catalog.php b/src/Services/Catalog/Catalog/Service/Catalog.php
index bf15208f..d9cb55fe 100644
--- a/src/Services/Catalog/Catalog/Service/Catalog.php
+++ b/src/Services/Catalog/Catalog/Service/Catalog.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Catalog/CatalogServiceBuilder.php b/src/Services/Catalog/CatalogServiceBuilder.php
index 32347b8c..b41933db 100644
--- a/src/Services/Catalog/CatalogServiceBuilder.php
+++ b/src/Services/Catalog/CatalogServiceBuilder.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Catalog/Common/ProductType.php b/src/Services/Catalog/Common/ProductType.php
index 0972c1a2..0bf8ef09 100644
--- a/src/Services/Catalog/Common/ProductType.php
+++ b/src/Services/Catalog/Common/ProductType.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Catalog/Common/Result/AbstractCatalogItem.php b/src/Services/Catalog/Common/Result/AbstractCatalogItem.php
index 25260f7d..7b6da5fd 100644
--- a/src/Services/Catalog/Common/Result/AbstractCatalogItem.php
+++ b/src/Services/Catalog/Common/Result/AbstractCatalogItem.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Catalog/Product/Result/ProductItemResult.php b/src/Services/Catalog/Product/Result/ProductItemResult.php
index 8eec07e9..c576d9b7 100644
--- a/src/Services/Catalog/Product/Result/ProductItemResult.php
+++ b/src/Services/Catalog/Product/Result/ProductItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Catalog/Product/Result/ProductResult.php b/src/Services/Catalog/Product/Result/ProductResult.php
index 9063e818..2751fda8 100644
--- a/src/Services/Catalog/Product/Result/ProductResult.php
+++ b/src/Services/Catalog/Product/Result/ProductResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Catalog/Product/Result/ProductsResult.php b/src/Services/Catalog/Product/Result/ProductsResult.php
index 9f80be4e..aa644fa3 100644
--- a/src/Services/Catalog/Product/Result/ProductsResult.php
+++ b/src/Services/Catalog/Product/Result/ProductsResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Catalog/Product/Service/Batch.php b/src/Services/Catalog/Product/Service/Batch.php
index 1bd42ef6..45dddcb7 100644
--- a/src/Services/Catalog/Product/Service/Batch.php
+++ b/src/Services/Catalog/Product/Service/Batch.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Catalog/Product/Service/Product.php b/src/Services/Catalog/Product/Service/Product.php
index 75b38cc6..730fd7c9 100644
--- a/src/Services/Catalog/Product/Service/Product.php
+++ b/src/Services/Catalog/Product/Service/Product.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/IM/IMServiceBuilder.php b/src/Services/IM/IMServiceBuilder.php
index d4a1d1e8..641eacd4 100644
--- a/src/Services/IM/IMServiceBuilder.php
+++ b/src/Services/IM/IMServiceBuilder.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/IM/Notify/Service/Notify.php b/src/Services/IM/Notify/Service/Notify.php
index c2c36c75..27deffa7 100644
--- a/src/Services/IM/Notify/Service/Notify.php
+++ b/src/Services/IM/Notify/Service/Notify.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/IMOpenLines/IMOpenLinesServiceBuilder.php b/src/Services/IMOpenLines/IMOpenLinesServiceBuilder.php
index 5643d5eb..8218dde8 100644
--- a/src/Services/IMOpenLines/IMOpenLinesServiceBuilder.php
+++ b/src/Services/IMOpenLines/IMOpenLinesServiceBuilder.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/IMOpenLines/Result/AddedMessageItemResult.php b/src/Services/IMOpenLines/Result/AddedMessageItemResult.php
index 9be1af30..c29eb4da 100644
--- a/src/Services/IMOpenLines/Result/AddedMessageItemResult.php
+++ b/src/Services/IMOpenLines/Result/AddedMessageItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/IMOpenLines/Result/JoinOpenLineResult.php b/src/Services/IMOpenLines/Result/JoinOpenLineResult.php
index 0e61a5be..a0a13a5e 100644
--- a/src/Services/IMOpenLines/Result/JoinOpenLineResult.php
+++ b/src/Services/IMOpenLines/Result/JoinOpenLineResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/IMOpenLines/Service/Network.php b/src/Services/IMOpenLines/Service/Network.php
index 2a9b0201..8d2c5720 100644
--- a/src/Services/IMOpenLines/Service/Network.php
+++ b/src/Services/IMOpenLines/Service/Network.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Main/Common/EventHandlerMetadata.php b/src/Services/Main/Common/EventHandlerMetadata.php
index 3c9dd2ca..3b6f6c7e 100644
--- a/src/Services/Main/Common/EventHandlerMetadata.php
+++ b/src/Services/Main/Common/EventHandlerMetadata.php
@@ -1,5 +1,14 @@
 
+ *
+ * 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;
diff --git a/src/Services/Main/MainServiceBuilder.php b/src/Services/Main/MainServiceBuilder.php
index 0b278032..b986a3a4 100644
--- a/src/Services/Main/MainServiceBuilder.php
+++ b/src/Services/Main/MainServiceBuilder.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Main/Result/ApplicationInfoItemResult.php b/src/Services/Main/Result/ApplicationInfoItemResult.php
index d76bd1fd..9d621709 100644
--- a/src/Services/Main/Result/ApplicationInfoItemResult.php
+++ b/src/Services/Main/Result/ApplicationInfoItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Main/Result/ApplicationInfoResult.php b/src/Services/Main/Result/ApplicationInfoResult.php
index b6c61fca..fcd58be8 100644
--- a/src/Services/Main/Result/ApplicationInfoResult.php
+++ b/src/Services/Main/Result/ApplicationInfoResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/Main/Result/EventHandlerBindResult.php b/src/Services/Main/Result/EventHandlerBindResult.php
index 69de0c5a..85a24630 100644
--- a/src/Services/Main/Result/EventHandlerBindResult.php
+++ b/src/Services/Main/Result/EventHandlerBindResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Main/Result/EventHandlerItemResult.php b/src/Services/Main/Result/EventHandlerItemResult.php
index 75c0a8c6..98a994a1 100644
--- a/src/Services/Main/Result/EventHandlerItemResult.php
+++ b/src/Services/Main/Result/EventHandlerItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Main/Result/EventHandlerUnbindResult.php b/src/Services/Main/Result/EventHandlerUnbindResult.php
index 35db152e..7c358b10 100644
--- a/src/Services/Main/Result/EventHandlerUnbindResult.php
+++ b/src/Services/Main/Result/EventHandlerUnbindResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Main/Result/EventHandlersResult.php b/src/Services/Main/Result/EventHandlersResult.php
index 7addf375..77a466ca 100644
--- a/src/Services/Main/Result/EventHandlersResult.php
+++ b/src/Services/Main/Result/EventHandlersResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Main/Result/EventListResult.php b/src/Services/Main/Result/EventListResult.php
index 83a87a35..d7733fc4 100644
--- a/src/Services/Main/Result/EventListResult.php
+++ b/src/Services/Main/Result/EventListResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Main/Result/IsUserAdminResult.php b/src/Services/Main/Result/IsUserAdminResult.php
index ef08fedd..ef68bc11 100644
--- a/src/Services/Main/Result/IsUserAdminResult.php
+++ b/src/Services/Main/Result/IsUserAdminResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Main/Result/MethodAffordabilityResult.php b/src/Services/Main/Result/MethodAffordabilityResult.php
index b4e2d068..4ca9c08a 100644
--- a/src/Services/Main/Result/MethodAffordabilityResult.php
+++ b/src/Services/Main/Result/MethodAffordabilityResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Main/Result/ServerTimeResult.php b/src/Services/Main/Result/ServerTimeResult.php
index 20c77c8c..819c3dc6 100644
--- a/src/Services/Main/Result/ServerTimeResult.php
+++ b/src/Services/Main/Result/ServerTimeResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Main/Result/UserProfileItemResult.php b/src/Services/Main/Result/UserProfileItemResult.php
index 46bbbf90..250db094 100644
--- a/src/Services/Main/Result/UserProfileItemResult.php
+++ b/src/Services/Main/Result/UserProfileItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Main/Result/UserProfileResult.php b/src/Services/Main/Result/UserProfileResult.php
index 2885e435..3826967f 100644
--- a/src/Services/Main/Result/UserProfileResult.php
+++ b/src/Services/Main/Result/UserProfileResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/Main/Service/Event.php b/src/Services/Main/Service/Event.php
index d8ffdb6a..cc733ddb 100644
--- a/src/Services/Main/Service/Event.php
+++ b/src/Services/Main/Service/Event.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Main/Service/EventManager.php b/src/Services/Main/Service/EventManager.php
index ffa74633..084e91ba 100644
--- a/src/Services/Main/Service/EventManager.php
+++ b/src/Services/Main/Service/EventManager.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Main/Service/Main.php b/src/Services/Main/Service/Main.php
index 215a2d9b..ad06d9a9 100644
--- a/src/Services/Main/Service/Main.php
+++ b/src/Services/Main/Service/Main.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Placement/PlacementServiceBuilder.php b/src/Services/Placement/PlacementServiceBuilder.php
index f06d86bd..cfefa8f9 100644
--- a/src/Services/Placement/PlacementServiceBuilder.php
+++ b/src/Services/Placement/PlacementServiceBuilder.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Placement/Result/DeleteUserTypeResult.php b/src/Services/Placement/Result/DeleteUserTypeResult.php
index 8714d0d4..67d01d05 100644
--- a/src/Services/Placement/Result/DeleteUserTypeResult.php
+++ b/src/Services/Placement/Result/DeleteUserTypeResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Placement/Result/PlacementBindResult.php b/src/Services/Placement/Result/PlacementBindResult.php
index 37bd628e..4cf00d6a 100644
--- a/src/Services/Placement/Result/PlacementBindResult.php
+++ b/src/Services/Placement/Result/PlacementBindResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Placement/Result/PlacementLocationCodesResult.php b/src/Services/Placement/Result/PlacementLocationCodesResult.php
index cc71af30..9490c7c7 100644
--- a/src/Services/Placement/Result/PlacementLocationCodesResult.php
+++ b/src/Services/Placement/Result/PlacementLocationCodesResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Placement/Result/PlacementLocationItemResult.php b/src/Services/Placement/Result/PlacementLocationItemResult.php
index 4b3b829b..5f0415c5 100644
--- a/src/Services/Placement/Result/PlacementLocationItemResult.php
+++ b/src/Services/Placement/Result/PlacementLocationItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Placement/Result/PlacementUnbindResult.php b/src/Services/Placement/Result/PlacementUnbindResult.php
index 0c882534..41e14e02 100644
--- a/src/Services/Placement/Result/PlacementUnbindResult.php
+++ b/src/Services/Placement/Result/PlacementUnbindResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Placement/Result/PlacementsLocationInformationResult.php b/src/Services/Placement/Result/PlacementsLocationInformationResult.php
index 328f3ae4..f817566e 100644
--- a/src/Services/Placement/Result/PlacementsLocationInformationResult.php
+++ b/src/Services/Placement/Result/PlacementsLocationInformationResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Placement/Result/RegisterUserTypeResult.php b/src/Services/Placement/Result/RegisterUserTypeResult.php
index 33f7f268..a72e7e60 100644
--- a/src/Services/Placement/Result/RegisterUserTypeResult.php
+++ b/src/Services/Placement/Result/RegisterUserTypeResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Placement/Result/UserFieldTypeItemResult.php b/src/Services/Placement/Result/UserFieldTypeItemResult.php
index 4ed69497..a0e80a6f 100644
--- a/src/Services/Placement/Result/UserFieldTypeItemResult.php
+++ b/src/Services/Placement/Result/UserFieldTypeItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Placement/Result/UserFieldTypesResult.php b/src/Services/Placement/Result/UserFieldTypesResult.php
index 5496a458..75e677cc 100644
--- a/src/Services/Placement/Result/UserFieldTypesResult.php
+++ b/src/Services/Placement/Result/UserFieldTypesResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Placement/Service/Placement.php b/src/Services/Placement/Service/Placement.php
index a364925e..ec302ecf 100644
--- a/src/Services/Placement/Service/Placement.php
+++ b/src/Services/Placement/Service/Placement.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Placement/Service/PlacementLocationCode.php b/src/Services/Placement/Service/PlacementLocationCode.php
index 32cb372a..9217e71d 100644
--- a/src/Services/Placement/Service/PlacementLocationCode.php
+++ b/src/Services/Placement/Service/PlacementLocationCode.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Placement/Service/UserFieldType.php b/src/Services/Placement/Service/UserFieldType.php
index f921f39c..75d706a4 100644
--- a/src/Services/Placement/Service/UserFieldType.php
+++ b/src/Services/Placement/Service/UserFieldType.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/ServiceBuilder.php b/src/Services/ServiceBuilder.php
index 8afda04e..8d646598 100644
--- a/src/Services/ServiceBuilder.php
+++ b/src/Services/ServiceBuilder.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 declare(strict_types=1);
 
 namespace Bitrix24\SDK\Services;
diff --git a/src/Services/ServiceBuilderFactory.php b/src/Services/ServiceBuilderFactory.php
index 3a19848c..dc44bac5 100644
--- a/src/Services/ServiceBuilderFactory.php
+++ b/src/Services/ServiceBuilderFactory.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 declare(strict_types=1);
 
 namespace Bitrix24\SDK\Services;
diff --git a/src/Services/Telephony/Call/Result/TranscriptAttachItemResult.php b/src/Services/Telephony/Call/Result/TranscriptAttachItemResult.php
index ef5945ba..3b60c3aa 100644
--- a/src/Services/Telephony/Call/Result/TranscriptAttachItemResult.php
+++ b/src/Services/Telephony/Call/Result/TranscriptAttachItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Call/Result/TranscriptAttachedResult.php b/src/Services/Telephony/Call/Result/TranscriptAttachedResult.php
index 0bdf3ae0..4738bce6 100644
--- a/src/Services/Telephony/Call/Result/TranscriptAttachedResult.php
+++ b/src/Services/Telephony/Call/Result/TranscriptAttachedResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Call/Service/Batch.php b/src/Services/Telephony/Call/Service/Batch.php
index 970df4af..19b02264 100644
--- a/src/Services/Telephony/Call/Service/Batch.php
+++ b/src/Services/Telephony/Call/Service/Batch.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Call/Service/Call.php b/src/Services/Telephony/Call/Service/Call.php
index 68be1cfc..206f4308 100644
--- a/src/Services/Telephony/Call/Service/Call.php
+++ b/src/Services/Telephony/Call/Service/Call.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Common/CallFailedCode.php b/src/Services/Telephony/Common/CallFailedCode.php
index 328578a9..1d61285f 100644
--- a/src/Services/Telephony/Common/CallFailedCode.php
+++ b/src/Services/Telephony/Common/CallFailedCode.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Common/CallType.php b/src/Services/Telephony/Common/CallType.php
index 1ff4fe89..74c7e0fb 100644
--- a/src/Services/Telephony/Common/CallType.php
+++ b/src/Services/Telephony/Common/CallType.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Common/CrmEntity.php b/src/Services/Telephony/Common/CrmEntity.php
index d8db3879..537522bc 100644
--- a/src/Services/Telephony/Common/CrmEntity.php
+++ b/src/Services/Telephony/Common/CrmEntity.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Common/CrmEntityType.php b/src/Services/Telephony/Common/CrmEntityType.php
index 529b06b6..4a34b6ff 100644
--- a/src/Services/Telephony/Common/CrmEntityType.php
+++ b/src/Services/Telephony/Common/CrmEntityType.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Common/PbxType.php b/src/Services/Telephony/Common/PbxType.php
index e6e07e81..b3233003 100644
--- a/src/Services/Telephony/Common/PbxType.php
+++ b/src/Services/Telephony/Common/PbxType.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Common/SipRegistrationStatus.php b/src/Services/Telephony/Common/SipRegistrationStatus.php
index 234475da..f4d10555 100644
--- a/src/Services/Telephony/Common/SipRegistrationStatus.php
+++ b/src/Services/Telephony/Common/SipRegistrationStatus.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Common/TelephonyCallStatusCode.php b/src/Services/Telephony/Common/TelephonyCallStatusCode.php
index d07bb2de..59aeb600 100644
--- a/src/Services/Telephony/Common/TelephonyCallStatusCode.php
+++ b/src/Services/Telephony/Common/TelephonyCallStatusCode.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Common/TranscriptMessage.php b/src/Services/Telephony/Common/TranscriptMessage.php
index 80ce22be..ca71ac97 100644
--- a/src/Services/Telephony/Common/TranscriptMessage.php
+++ b/src/Services/Telephony/Common/TranscriptMessage.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Common/TranscriptMessageSide.php b/src/Services/Telephony/Common/TranscriptMessageSide.php
index 9acd7a1a..529fffd8 100644
--- a/src/Services/Telephony/Common/TranscriptMessageSide.php
+++ b/src/Services/Telephony/Common/TranscriptMessageSide.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Events/OnExternalCallBackStart/OnExternalCallBackStart.php b/src/Services/Telephony/Events/OnExternalCallBackStart/OnExternalCallBackStart.php
index 41ec1624..57e23965 100644
--- a/src/Services/Telephony/Events/OnExternalCallBackStart/OnExternalCallBackStart.php
+++ b/src/Services/Telephony/Events/OnExternalCallBackStart/OnExternalCallBackStart.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Events/OnExternalCallBackStart/OnExternalCallBackStartEventPayload.php b/src/Services/Telephony/Events/OnExternalCallBackStart/OnExternalCallBackStartEventPayload.php
index c78653ee..4b36c9ed 100644
--- a/src/Services/Telephony/Events/OnExternalCallBackStart/OnExternalCallBackStartEventPayload.php
+++ b/src/Services/Telephony/Events/OnExternalCallBackStart/OnExternalCallBackStartEventPayload.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Events/OnExternalCallStart/OnExternalCallStart.php b/src/Services/Telephony/Events/OnExternalCallStart/OnExternalCallStart.php
index d9ec396d..f6a450d6 100644
--- a/src/Services/Telephony/Events/OnExternalCallStart/OnExternalCallStart.php
+++ b/src/Services/Telephony/Events/OnExternalCallStart/OnExternalCallStart.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Events/OnExternalCallStart/OnExternalCallStartEventPayload.php b/src/Services/Telephony/Events/OnExternalCallStart/OnExternalCallStartEventPayload.php
index 7a57d2af..5e747e4c 100644
--- a/src/Services/Telephony/Events/OnExternalCallStart/OnExternalCallStartEventPayload.php
+++ b/src/Services/Telephony/Events/OnExternalCallStart/OnExternalCallStartEventPayload.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Events/OnVoximplantCallEnd/OnVoximplantCallEnd.php b/src/Services/Telephony/Events/OnVoximplantCallEnd/OnVoximplantCallEnd.php
index d277a1c9..0c8cc335 100644
--- a/src/Services/Telephony/Events/OnVoximplantCallEnd/OnVoximplantCallEnd.php
+++ b/src/Services/Telephony/Events/OnVoximplantCallEnd/OnVoximplantCallEnd.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Events/OnVoximplantCallEnd/OnVoximplantCallEndEventPayload.php b/src/Services/Telephony/Events/OnVoximplantCallEnd/OnVoximplantCallEndEventPayload.php
index 6e8cd2fc..32f7dbd9 100644
--- a/src/Services/Telephony/Events/OnVoximplantCallEnd/OnVoximplantCallEndEventPayload.php
+++ b/src/Services/Telephony/Events/OnVoximplantCallEnd/OnVoximplantCallEndEventPayload.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Events/OnVoximplantCallInit/OnVoximplantCallInit.php b/src/Services/Telephony/Events/OnVoximplantCallInit/OnVoximplantCallInit.php
index f21a93fb..cc29ce27 100644
--- a/src/Services/Telephony/Events/OnVoximplantCallInit/OnVoximplantCallInit.php
+++ b/src/Services/Telephony/Events/OnVoximplantCallInit/OnVoximplantCallInit.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Events/OnVoximplantCallInit/OnVoximplantCallInitEventPayload.php b/src/Services/Telephony/Events/OnVoximplantCallInit/OnVoximplantCallInitEventPayload.php
index 057a66dc..f9aad78c 100644
--- a/src/Services/Telephony/Events/OnVoximplantCallInit/OnVoximplantCallInitEventPayload.php
+++ b/src/Services/Telephony/Events/OnVoximplantCallInit/OnVoximplantCallInitEventPayload.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Events/OnVoximplantCallStart/OnVoximplantCallStart.php b/src/Services/Telephony/Events/OnVoximplantCallStart/OnVoximplantCallStart.php
index 186aeecf..a78c3586 100644
--- a/src/Services/Telephony/Events/OnVoximplantCallStart/OnVoximplantCallStart.php
+++ b/src/Services/Telephony/Events/OnVoximplantCallStart/OnVoximplantCallStart.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Events/OnVoximplantCallStart/OnVoximplantCallStartEventPayload.php b/src/Services/Telephony/Events/OnVoximplantCallStart/OnVoximplantCallStartEventPayload.php
index e7b6ff44..c67036b4 100644
--- a/src/Services/Telephony/Events/OnVoximplantCallStart/OnVoximplantCallStartEventPayload.php
+++ b/src/Services/Telephony/Events/OnVoximplantCallStart/OnVoximplantCallStartEventPayload.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Events/TelephonyEventsFabric.php b/src/Services/Telephony/Events/TelephonyEventsFabric.php
index 6bfe978d..e19f2f44 100644
--- a/src/Services/Telephony/Events/TelephonyEventsFabric.php
+++ b/src/Services/Telephony/Events/TelephonyEventsFabric.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 declare(strict_types=1);
 
 
diff --git a/src/Services/Telephony/ExternalCall/Result/CallRecordFileUploadedItemResult.php b/src/Services/Telephony/ExternalCall/Result/CallRecordFileUploadedItemResult.php
index 8abf0d14..9c516464 100644
--- a/src/Services/Telephony/ExternalCall/Result/CallRecordFileUploadedItemResult.php
+++ b/src/Services/Telephony/ExternalCall/Result/CallRecordFileUploadedItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/ExternalCall/Result/CallRecordFileUploadedResult.php b/src/Services/Telephony/ExternalCall/Result/CallRecordFileUploadedResult.php
index 42d5cd02..ea448047 100644
--- a/src/Services/Telephony/ExternalCall/Result/CallRecordFileUploadedResult.php
+++ b/src/Services/Telephony/ExternalCall/Result/CallRecordFileUploadedResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/ExternalCall/Result/CallRecordUploadUrlItemResult.php b/src/Services/Telephony/ExternalCall/Result/CallRecordUploadUrlItemResult.php
index ea4c35c3..1c6524de 100644
--- a/src/Services/Telephony/ExternalCall/Result/CallRecordUploadUrlItemResult.php
+++ b/src/Services/Telephony/ExternalCall/Result/CallRecordUploadUrlItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/ExternalCall/Result/CallRecordUploadUrlResult.php b/src/Services/Telephony/ExternalCall/Result/CallRecordUploadUrlResult.php
index 7849b8a3..566385c6 100644
--- a/src/Services/Telephony/ExternalCall/Result/CallRecordUploadUrlResult.php
+++ b/src/Services/Telephony/ExternalCall/Result/CallRecordUploadUrlResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/ExternalCall/Result/ExternalCallFinishedItemResult.php b/src/Services/Telephony/ExternalCall/Result/ExternalCallFinishedItemResult.php
index 72f4189a..64e0d5cf 100644
--- a/src/Services/Telephony/ExternalCall/Result/ExternalCallFinishedItemResult.php
+++ b/src/Services/Telephony/ExternalCall/Result/ExternalCallFinishedItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/ExternalCall/Result/ExternalCallFinishedResult.php b/src/Services/Telephony/ExternalCall/Result/ExternalCallFinishedResult.php
index fcd8aa1c..b6baae82 100644
--- a/src/Services/Telephony/ExternalCall/Result/ExternalCallFinishedResult.php
+++ b/src/Services/Telephony/ExternalCall/Result/ExternalCallFinishedResult.php
@@ -1,5 +1,15 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/ExternalCall/Result/ExternalCallRegisteredItemResult.php b/src/Services/Telephony/ExternalCall/Result/ExternalCallRegisteredItemResult.php
index 65deebb8..1bfb63c0 100644
--- a/src/Services/Telephony/ExternalCall/Result/ExternalCallRegisteredItemResult.php
+++ b/src/Services/Telephony/ExternalCall/Result/ExternalCallRegisteredItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/ExternalCall/Result/ExternalCallRegisteredResult.php b/src/Services/Telephony/ExternalCall/Result/ExternalCallRegisteredResult.php
index b43696f1..72d84f7f 100644
--- a/src/Services/Telephony/ExternalCall/Result/ExternalCallRegisteredResult.php
+++ b/src/Services/Telephony/ExternalCall/Result/ExternalCallRegisteredResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/ExternalCall/Result/SearchCrmEntitiesItemResult.php b/src/Services/Telephony/ExternalCall/Result/SearchCrmEntitiesItemResult.php
index 68401e49..ad65555d 100644
--- a/src/Services/Telephony/ExternalCall/Result/SearchCrmEntitiesItemResult.php
+++ b/src/Services/Telephony/ExternalCall/Result/SearchCrmEntitiesItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/ExternalCall/Result/SearchCrmEntitiesResult.php b/src/Services/Telephony/ExternalCall/Result/SearchCrmEntitiesResult.php
index db2f1df5..8034e77e 100644
--- a/src/Services/Telephony/ExternalCall/Result/SearchCrmEntitiesResult.php
+++ b/src/Services/Telephony/ExternalCall/Result/SearchCrmEntitiesResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/ExternalCall/Result/UserDigestItemResult.php b/src/Services/Telephony/ExternalCall/Result/UserDigestItemResult.php
index 62585ca6..d74ff7b5 100644
--- a/src/Services/Telephony/ExternalCall/Result/UserDigestItemResult.php
+++ b/src/Services/Telephony/ExternalCall/Result/UserDigestItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/ExternalCall/Service/Batch.php b/src/Services/Telephony/ExternalCall/Service/Batch.php
index 111e4c9c..3e9a4956 100644
--- a/src/Services/Telephony/ExternalCall/Service/Batch.php
+++ b/src/Services/Telephony/ExternalCall/Service/Batch.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/ExternalCall/Service/ExternalCall.php b/src/Services/Telephony/ExternalCall/Service/ExternalCall.php
index 98cc1180..b7ca7d6d 100644
--- a/src/Services/Telephony/ExternalCall/Service/ExternalCall.php
+++ b/src/Services/Telephony/ExternalCall/Service/ExternalCall.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/ExternalLine/Result/ExternalLineAddItemResult.php b/src/Services/Telephony/ExternalLine/Result/ExternalLineAddItemResult.php
index 87cbbf75..34cfe9d8 100644
--- a/src/Services/Telephony/ExternalLine/Result/ExternalLineAddItemResult.php
+++ b/src/Services/Telephony/ExternalLine/Result/ExternalLineAddItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/ExternalLine/Result/ExternalLineAddedResult.php b/src/Services/Telephony/ExternalLine/Result/ExternalLineAddedResult.php
index f9fbf926..08755af2 100644
--- a/src/Services/Telephony/ExternalLine/Result/ExternalLineAddedResult.php
+++ b/src/Services/Telephony/ExternalLine/Result/ExternalLineAddedResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/ExternalLine/Result/ExternalLineItemResult.php b/src/Services/Telephony/ExternalLine/Result/ExternalLineItemResult.php
index ae13aa3d..24f3e585 100644
--- a/src/Services/Telephony/ExternalLine/Result/ExternalLineItemResult.php
+++ b/src/Services/Telephony/ExternalLine/Result/ExternalLineItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/ExternalLine/Result/ExternalLinesResult.php b/src/Services/Telephony/ExternalLine/Result/ExternalLinesResult.php
index 97599289..24620127 100644
--- a/src/Services/Telephony/ExternalLine/Result/ExternalLinesResult.php
+++ b/src/Services/Telephony/ExternalLine/Result/ExternalLinesResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/ExternalLine/Service/Batch.php b/src/Services/Telephony/ExternalLine/Service/Batch.php
index 2bf29666..7f747eed 100644
--- a/src/Services/Telephony/ExternalLine/Service/Batch.php
+++ b/src/Services/Telephony/ExternalLine/Service/Batch.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/ExternalLine/Service/ExternalLine.php b/src/Services/Telephony/ExternalLine/Service/ExternalLine.php
index b9169af1..1156b3e9 100644
--- a/src/Services/Telephony/ExternalLine/Service/ExternalLine.php
+++ b/src/Services/Telephony/ExternalLine/Service/ExternalLine.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/TelephonyServiceBuilder.php b/src/Services/Telephony/TelephonyServiceBuilder.php
index c5b79457..6d872b31 100644
--- a/src/Services/Telephony/TelephonyServiceBuilder.php
+++ b/src/Services/Telephony/TelephonyServiceBuilder.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/InfoCall/Result/VoximplantInfoCallItemResult.php b/src/Services/Telephony/Voximplant/InfoCall/Result/VoximplantInfoCallItemResult.php
index 6ca811c2..44105010 100644
--- a/src/Services/Telephony/Voximplant/InfoCall/Result/VoximplantInfoCallItemResult.php
+++ b/src/Services/Telephony/Voximplant/InfoCall/Result/VoximplantInfoCallItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/InfoCall/Result/VoximplantInfoCallResult.php b/src/Services/Telephony/Voximplant/InfoCall/Result/VoximplantInfoCallResult.php
index 2dd9a86e..f84fe59e 100644
--- a/src/Services/Telephony/Voximplant/InfoCall/Result/VoximplantInfoCallResult.php
+++ b/src/Services/Telephony/Voximplant/InfoCall/Result/VoximplantInfoCallResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/InfoCall/Service/Batch.php b/src/Services/Telephony/Voximplant/InfoCall/Service/Batch.php
index 54f1bf39..40f1dec5 100644
--- a/src/Services/Telephony/Voximplant/InfoCall/Service/Batch.php
+++ b/src/Services/Telephony/Voximplant/InfoCall/Service/Batch.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/InfoCall/Service/InfoCall.php b/src/Services/Telephony/Voximplant/InfoCall/Service/InfoCall.php
index a88266a9..74a0e9a4 100644
--- a/src/Services/Telephony/Voximplant/InfoCall/Service/InfoCall.php
+++ b/src/Services/Telephony/Voximplant/InfoCall/Service/InfoCall.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/Line/Result/VoximplantLineIdItemResult.php b/src/Services/Telephony/Voximplant/Line/Result/VoximplantLineIdItemResult.php
index ddbdffec..1f7b6172 100644
--- a/src/Services/Telephony/Voximplant/Line/Result/VoximplantLineIdItemResult.php
+++ b/src/Services/Telephony/Voximplant/Line/Result/VoximplantLineIdItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/Line/Result/VoximplantLineIdResult.php b/src/Services/Telephony/Voximplant/Line/Result/VoximplantLineIdResult.php
index deccd1db..517e334c 100644
--- a/src/Services/Telephony/Voximplant/Line/Result/VoximplantLineIdResult.php
+++ b/src/Services/Telephony/Voximplant/Line/Result/VoximplantLineIdResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/Line/Result/VoximplantLineItemResult.php b/src/Services/Telephony/Voximplant/Line/Result/VoximplantLineItemResult.php
index 616591df..acd04a4d 100644
--- a/src/Services/Telephony/Voximplant/Line/Result/VoximplantLineItemResult.php
+++ b/src/Services/Telephony/Voximplant/Line/Result/VoximplantLineItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/Line/Result/VoximplantLinesResult.php b/src/Services/Telephony/Voximplant/Line/Result/VoximplantLinesResult.php
index b2fcc19c..3069b32e 100644
--- a/src/Services/Telephony/Voximplant/Line/Result/VoximplantLinesResult.php
+++ b/src/Services/Telephony/Voximplant/Line/Result/VoximplantLinesResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/Telephony/Voximplant/Line/Service/Batch.php b/src/Services/Telephony/Voximplant/Line/Service/Batch.php
index 44e54e41..ddc7759b 100644
--- a/src/Services/Telephony/Voximplant/Line/Service/Batch.php
+++ b/src/Services/Telephony/Voximplant/Line/Service/Batch.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/Line/Service/Line.php b/src/Services/Telephony/Voximplant/Line/Service/Line.php
index bfc873f8..e4e9ee20 100644
--- a/src/Services/Telephony/Voximplant/Line/Service/Line.php
+++ b/src/Services/Telephony/Voximplant/Line/Service/Line.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/Sip/Result/SipConnectorStatusItemResult.php b/src/Services/Telephony/Voximplant/Sip/Result/SipConnectorStatusItemResult.php
index 9d13191e..3a8c330a 100644
--- a/src/Services/Telephony/Voximplant/Sip/Result/SipConnectorStatusItemResult.php
+++ b/src/Services/Telephony/Voximplant/Sip/Result/SipConnectorStatusItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/Sip/Result/SipConnectorStatusResult.php b/src/Services/Telephony/Voximplant/Sip/Result/SipConnectorStatusResult.php
index e6a521c3..1df8ce4f 100644
--- a/src/Services/Telephony/Voximplant/Sip/Result/SipConnectorStatusResult.php
+++ b/src/Services/Telephony/Voximplant/Sip/Result/SipConnectorStatusResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/Sip/Result/SipLineAddedResult.php b/src/Services/Telephony/Voximplant/Sip/Result/SipLineAddedResult.php
index 2701cb83..3df894d0 100644
--- a/src/Services/Telephony/Voximplant/Sip/Result/SipLineAddedResult.php
+++ b/src/Services/Telephony/Voximplant/Sip/Result/SipLineAddedResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/Sip/Result/SipLineItemResult.php b/src/Services/Telephony/Voximplant/Sip/Result/SipLineItemResult.php
index 117e3e41..3ee86ada 100644
--- a/src/Services/Telephony/Voximplant/Sip/Result/SipLineItemResult.php
+++ b/src/Services/Telephony/Voximplant/Sip/Result/SipLineItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/Sip/Result/SipLineStatusItemResult.php b/src/Services/Telephony/Voximplant/Sip/Result/SipLineStatusItemResult.php
index 79f21f9f..3480d135 100644
--- a/src/Services/Telephony/Voximplant/Sip/Result/SipLineStatusItemResult.php
+++ b/src/Services/Telephony/Voximplant/Sip/Result/SipLineStatusItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/Sip/Result/SipLineStatusResult.php b/src/Services/Telephony/Voximplant/Sip/Result/SipLineStatusResult.php
index 3fd1dab0..94078b3d 100644
--- a/src/Services/Telephony/Voximplant/Sip/Result/SipLineStatusResult.php
+++ b/src/Services/Telephony/Voximplant/Sip/Result/SipLineStatusResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/Sip/Result/SipLinesResult.php b/src/Services/Telephony/Voximplant/Sip/Result/SipLinesResult.php
index 4ff7bfce..1abba0d0 100644
--- a/src/Services/Telephony/Voximplant/Sip/Result/SipLinesResult.php
+++ b/src/Services/Telephony/Voximplant/Sip/Result/SipLinesResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/Telephony/Voximplant/Sip/Service/Batch.php b/src/Services/Telephony/Voximplant/Sip/Service/Batch.php
index 2a458e34..860cb617 100644
--- a/src/Services/Telephony/Voximplant/Sip/Service/Batch.php
+++ b/src/Services/Telephony/Voximplant/Sip/Service/Batch.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/Sip/Service/Sip.php b/src/Services/Telephony/Voximplant/Sip/Service/Sip.php
index a310e2c1..600bb347 100644
--- a/src/Services/Telephony/Voximplant/Sip/Service/Sip.php
+++ b/src/Services/Telephony/Voximplant/Sip/Service/Sip.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/TTS/Voices/Result/VoximplantVoiceItemResult.php b/src/Services/Telephony/Voximplant/TTS/Voices/Result/VoximplantVoiceItemResult.php
index 1e249e33..acd636d3 100644
--- a/src/Services/Telephony/Voximplant/TTS/Voices/Result/VoximplantVoiceItemResult.php
+++ b/src/Services/Telephony/Voximplant/TTS/Voices/Result/VoximplantVoiceItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/TTS/Voices/Result/VoximplantVoicesResult.php b/src/Services/Telephony/Voximplant/TTS/Voices/Result/VoximplantVoicesResult.php
index fb0b4a5c..b0c7beed 100644
--- a/src/Services/Telephony/Voximplant/TTS/Voices/Result/VoximplantVoicesResult.php
+++ b/src/Services/Telephony/Voximplant/TTS/Voices/Result/VoximplantVoicesResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/Telephony/Voximplant/TTS/Voices/Service/Batch.php b/src/Services/Telephony/Voximplant/TTS/Voices/Service/Batch.php
index cc6cea9a..b08b5f89 100644
--- a/src/Services/Telephony/Voximplant/TTS/Voices/Service/Batch.php
+++ b/src/Services/Telephony/Voximplant/TTS/Voices/Service/Batch.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/TTS/Voices/Service/Voices.php b/src/Services/Telephony/Voximplant/TTS/Voices/Service/Voices.php
index b8a000e2..6428f39a 100644
--- a/src/Services/Telephony/Voximplant/TTS/Voices/Service/Voices.php
+++ b/src/Services/Telephony/Voximplant/TTS/Voices/Service/Voices.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/Url/Result/VoximplantPagesItemResult.php b/src/Services/Telephony/Voximplant/Url/Result/VoximplantPagesItemResult.php
index 67eab9fa..54e75210 100644
--- a/src/Services/Telephony/Voximplant/Url/Result/VoximplantPagesItemResult.php
+++ b/src/Services/Telephony/Voximplant/Url/Result/VoximplantPagesItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/Url/Result/VoximplantPagesResult.php b/src/Services/Telephony/Voximplant/Url/Result/VoximplantPagesResult.php
index cb1eea78..48ba7581 100644
--- a/src/Services/Telephony/Voximplant/Url/Result/VoximplantPagesResult.php
+++ b/src/Services/Telephony/Voximplant/Url/Result/VoximplantPagesResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/Url/Service/Batch.php b/src/Services/Telephony/Voximplant/Url/Service/Batch.php
index 1f5e6b7b..362fcd67 100644
--- a/src/Services/Telephony/Voximplant/Url/Service/Batch.php
+++ b/src/Services/Telephony/Voximplant/Url/Service/Batch.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/Url/Service/Url.php b/src/Services/Telephony/Voximplant/Url/Service/Url.php
index d738bff6..0e43112a 100644
--- a/src/Services/Telephony/Voximplant/Url/Service/Url.php
+++ b/src/Services/Telephony/Voximplant/Url/Service/Url.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/User/Result/VoximplantUserSettingsItemResult.php b/src/Services/Telephony/Voximplant/User/Result/VoximplantUserSettingsItemResult.php
index fa7007a0..e55eece5 100644
--- a/src/Services/Telephony/Voximplant/User/Result/VoximplantUserSettingsItemResult.php
+++ b/src/Services/Telephony/Voximplant/User/Result/VoximplantUserSettingsItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/User/Result/VoximplantUserSettingsResult.php b/src/Services/Telephony/Voximplant/User/Result/VoximplantUserSettingsResult.php
index f5eeaa8e..e992d305 100644
--- a/src/Services/Telephony/Voximplant/User/Result/VoximplantUserSettingsResult.php
+++ b/src/Services/Telephony/Voximplant/User/Result/VoximplantUserSettingsResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/User/Service/Batch.php b/src/Services/Telephony/Voximplant/User/Service/Batch.php
index aab41d26..90593a2c 100644
--- a/src/Services/Telephony/Voximplant/User/Service/Batch.php
+++ b/src/Services/Telephony/Voximplant/User/Service/Batch.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/User/Service/User.php b/src/Services/Telephony/Voximplant/User/Service/User.php
index cd163b13..cc59ccd8 100644
--- a/src/Services/Telephony/Voximplant/User/Service/User.php
+++ b/src/Services/Telephony/Voximplant/User/Service/User.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Telephony/Voximplant/VoximplantServiceBuilder.php b/src/Services/Telephony/Voximplant/VoximplantServiceBuilder.php
index 99215854..1bb65ad9 100644
--- a/src/Services/Telephony/Voximplant/VoximplantServiceBuilder.php
+++ b/src/Services/Telephony/Voximplant/VoximplantServiceBuilder.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/User/Result/UserItemResult.php b/src/Services/User/Result/UserItemResult.php
index de8b597e..bd4061c9 100644
--- a/src/Services/User/Result/UserItemResult.php
+++ b/src/Services/User/Result/UserItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/User/Result/UserResult.php b/src/Services/User/Result/UserResult.php
index 01e0ee4b..928a6697 100644
--- a/src/Services/User/Result/UserResult.php
+++ b/src/Services/User/Result/UserResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/User/Result/UsersResult.php b/src/Services/User/Result/UsersResult.php
index a4fff780..94881973 100644
--- a/src/Services/User/Result/UsersResult.php
+++ b/src/Services/User/Result/UsersResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/User/Service/User.php b/src/Services/User/Service/User.php
index 18ba6426..13c55978 100644
--- a/src/Services/User/Service/User.php
+++ b/src/Services/User/Service/User.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/User/UserServiceBuilder.php b/src/Services/User/UserServiceBuilder.php
index 7b69235d..aee42ca8 100644
--- a/src/Services/User/UserServiceBuilder.php
+++ b/src/Services/User/UserServiceBuilder.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/UserConsent/Result/UserConsentAgreementItemResult.php b/src/Services/UserConsent/Result/UserConsentAgreementItemResult.php
index 90147522..cc802d3c 100644
--- a/src/Services/UserConsent/Result/UserConsentAgreementItemResult.php
+++ b/src/Services/UserConsent/Result/UserConsentAgreementItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/UserConsent/Result/UserConsentAgreementResult.php b/src/Services/UserConsent/Result/UserConsentAgreementResult.php
index 3b9cd274..2763d672 100644
--- a/src/Services/UserConsent/Result/UserConsentAgreementResult.php
+++ b/src/Services/UserConsent/Result/UserConsentAgreementResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/UserConsent/Result/UserConsentAgreementTextItemResult.php b/src/Services/UserConsent/Result/UserConsentAgreementTextItemResult.php
index 099efd59..7778443b 100644
--- a/src/Services/UserConsent/Result/UserConsentAgreementTextItemResult.php
+++ b/src/Services/UserConsent/Result/UserConsentAgreementTextItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/UserConsent/Result/UserConsentAgreementTextResult.php b/src/Services/UserConsent/Result/UserConsentAgreementTextResult.php
index 713c779b..647b8e21 100644
--- a/src/Services/UserConsent/Result/UserConsentAgreementTextResult.php
+++ b/src/Services/UserConsent/Result/UserConsentAgreementTextResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/UserConsent/Result/UserConsentAgreementsResult.php b/src/Services/UserConsent/Result/UserConsentAgreementsResult.php
index 0992ef0d..be4ce952 100644
--- a/src/Services/UserConsent/Result/UserConsentAgreementsResult.php
+++ b/src/Services/UserConsent/Result/UserConsentAgreementsResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and license information, please view the MIT-LICENSE.txt
+ * file that was distributed with this source code.
+ */
+
 
 declare(strict_types=1);
 
diff --git a/src/Services/UserConsent/Service/UserConsent.php b/src/Services/UserConsent/Service/UserConsent.php
index 02a3a6f8..95eac67d 100644
--- a/src/Services/UserConsent/Service/UserConsent.php
+++ b/src/Services/UserConsent/Service/UserConsent.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/UserConsent/Service/UserConsentAgreement.php b/src/Services/UserConsent/Service/UserConsentAgreement.php
index 988764e9..b4c97b81 100644
--- a/src/Services/UserConsent/Service/UserConsentAgreement.php
+++ b/src/Services/UserConsent/Service/UserConsentAgreement.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/UserConsent/UserConsentServiceBuilder.php b/src/Services/UserConsent/UserConsentServiceBuilder.php
index e1acfaf0..fa6cb423 100644
--- a/src/Services/UserConsent/UserConsentServiceBuilder.php
+++ b/src/Services/UserConsent/UserConsentServiceBuilder.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Activity/Result/AddedActivityResult.php b/src/Services/Workflows/Activity/Result/AddedActivityResult.php
index 676c1217..0c786929 100644
--- a/src/Services/Workflows/Activity/Result/AddedActivityResult.php
+++ b/src/Services/Workflows/Activity/Result/AddedActivityResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Activity/Result/AddedMessageToLogResult.php b/src/Services/Workflows/Activity/Result/AddedMessageToLogResult.php
index ca90c650..fc5e0201 100644
--- a/src/Services/Workflows/Activity/Result/AddedMessageToLogResult.php
+++ b/src/Services/Workflows/Activity/Result/AddedMessageToLogResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Activity/Result/UpdateActivityResult.php b/src/Services/Workflows/Activity/Result/UpdateActivityResult.php
index 99926003..e370949e 100644
--- a/src/Services/Workflows/Activity/Result/UpdateActivityResult.php
+++ b/src/Services/Workflows/Activity/Result/UpdateActivityResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Activity/Result/WorkflowActivitiesResult.php b/src/Services/Workflows/Activity/Result/WorkflowActivitiesResult.php
index 1b140482..aef541fd 100644
--- a/src/Services/Workflows/Activity/Result/WorkflowActivitiesResult.php
+++ b/src/Services/Workflows/Activity/Result/WorkflowActivitiesResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Activity/Service/Activity.php b/src/Services/Workflows/Activity/Service/Activity.php
index 4360fea1..b6f94f75 100644
--- a/src/Services/Workflows/Activity/Service/Activity.php
+++ b/src/Services/Workflows/Activity/Service/Activity.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Activity/Service/Batch.php b/src/Services/Workflows/Activity/Service/Batch.php
index 07d3fdb7..aa6ee33a 100644
--- a/src/Services/Workflows/Activity/Service/Batch.php
+++ b/src/Services/Workflows/Activity/Service/Batch.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Common/Auth.php b/src/Services/Workflows/Common/Auth.php
index be50a388..8988357f 100644
--- a/src/Services/Workflows/Common/Auth.php
+++ b/src/Services/Workflows/Common/Auth.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Common/DocumentType.php b/src/Services/Workflows/Common/DocumentType.php
index cffde998..3bca1e40 100644
--- a/src/Services/Workflows/Common/DocumentType.php
+++ b/src/Services/Workflows/Common/DocumentType.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Common/WorkflowAutoExecutionType.php b/src/Services/Workflows/Common/WorkflowAutoExecutionType.php
index d8684bce..1eae76bb 100644
--- a/src/Services/Workflows/Common/WorkflowAutoExecutionType.php
+++ b/src/Services/Workflows/Common/WorkflowAutoExecutionType.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Common/WorkflowDocumentId.php b/src/Services/Workflows/Common/WorkflowDocumentId.php
index 01c67772..63fdafbd 100644
--- a/src/Services/Workflows/Common/WorkflowDocumentId.php
+++ b/src/Services/Workflows/Common/WorkflowDocumentId.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Common/WorkflowDocumentType.php b/src/Services/Workflows/Common/WorkflowDocumentType.php
index 759621b6..e1bbe0ca 100644
--- a/src/Services/Workflows/Common/WorkflowDocumentType.php
+++ b/src/Services/Workflows/Common/WorkflowDocumentType.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Common/WorkflowPropertyType.php b/src/Services/Workflows/Common/WorkflowPropertyType.php
index 4ff90cf9..6ec69804 100644
--- a/src/Services/Workflows/Common/WorkflowPropertyType.php
+++ b/src/Services/Workflows/Common/WorkflowPropertyType.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Common/WorkflowTaskActivityType.php b/src/Services/Workflows/Common/WorkflowTaskActivityType.php
index e7fba294..76945f80 100644
--- a/src/Services/Workflows/Common/WorkflowTaskActivityType.php
+++ b/src/Services/Workflows/Common/WorkflowTaskActivityType.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Common/WorkflowTaskCompleteStatusType.php b/src/Services/Workflows/Common/WorkflowTaskCompleteStatusType.php
index d03867b8..52d5622b 100644
--- a/src/Services/Workflows/Common/WorkflowTaskCompleteStatusType.php
+++ b/src/Services/Workflows/Common/WorkflowTaskCompleteStatusType.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Common/WorkflowTaskStatusType.php b/src/Services/Workflows/Common/WorkflowTaskStatusType.php
index 78872afc..9389ddca 100644
--- a/src/Services/Workflows/Common/WorkflowTaskStatusType.php
+++ b/src/Services/Workflows/Common/WorkflowTaskStatusType.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Common/WorkflowTaskUserStatusType.php b/src/Services/Workflows/Common/WorkflowTaskUserStatusType.php
index 51910fde..d0fc40df 100644
--- a/src/Services/Workflows/Common/WorkflowTaskUserStatusType.php
+++ b/src/Services/Workflows/Common/WorkflowTaskUserStatusType.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Event/Result/EventSendResult.php b/src/Services/Workflows/Event/Result/EventSendResult.php
index c5acfee5..32b87ee7 100644
--- a/src/Services/Workflows/Event/Result/EventSendResult.php
+++ b/src/Services/Workflows/Event/Result/EventSendResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Event/Service/Batch.php b/src/Services/Workflows/Event/Service/Batch.php
index feaba616..9252244d 100644
--- a/src/Services/Workflows/Event/Service/Batch.php
+++ b/src/Services/Workflows/Event/Service/Batch.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Event/Service/Event.php b/src/Services/Workflows/Event/Service/Event.php
index 5596625b..7cbe4eba 100644
--- a/src/Services/Workflows/Event/Service/Event.php
+++ b/src/Services/Workflows/Event/Service/Event.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Exceptions/ActivityOrRobotAlreadyInstalledException.php b/src/Services/Workflows/Exceptions/ActivityOrRobotAlreadyInstalledException.php
index bb3ee0e6..c6574be2 100644
--- a/src/Services/Workflows/Exceptions/ActivityOrRobotAlreadyInstalledException.php
+++ b/src/Services/Workflows/Exceptions/ActivityOrRobotAlreadyInstalledException.php
@@ -1,5 +1,14 @@
 
+ *
+ * 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;
diff --git a/src/Services/Workflows/Exceptions/ActivityOrRobotValidationFailureException.php b/src/Services/Workflows/Exceptions/ActivityOrRobotValidationFailureException.php
index 8dd148f7..2dd24998 100644
--- a/src/Services/Workflows/Exceptions/ActivityOrRobotValidationFailureException.php
+++ b/src/Services/Workflows/Exceptions/ActivityOrRobotValidationFailureException.php
@@ -1,5 +1,14 @@
 
+ *
+ * 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;
diff --git a/src/Services/Workflows/Exceptions/WorkflowTaskAlreadyCompletedException.php b/src/Services/Workflows/Exceptions/WorkflowTaskAlreadyCompletedException.php
index 83a611ad..af26237f 100644
--- a/src/Services/Workflows/Exceptions/WorkflowTaskAlreadyCompletedException.php
+++ b/src/Services/Workflows/Exceptions/WorkflowTaskAlreadyCompletedException.php
@@ -1,5 +1,14 @@
 
+ *
+ * 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;
diff --git a/src/Services/Workflows/Robot/Request/IncomingRobotRequest.php b/src/Services/Workflows/Robot/Request/IncomingRobotRequest.php
index 679ad196..859d9a64 100644
--- a/src/Services/Workflows/Robot/Request/IncomingRobotRequest.php
+++ b/src/Services/Workflows/Robot/Request/IncomingRobotRequest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Robot/Result/AddedRobotResult.php b/src/Services/Workflows/Robot/Result/AddedRobotResult.php
index 93c1bb18..5888cb64 100644
--- a/src/Services/Workflows/Robot/Result/AddedRobotResult.php
+++ b/src/Services/Workflows/Robot/Result/AddedRobotResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Robot/Result/UpdateRobotResult.php b/src/Services/Workflows/Robot/Result/UpdateRobotResult.php
index fe2d2c3b..5e7615d9 100644
--- a/src/Services/Workflows/Robot/Result/UpdateRobotResult.php
+++ b/src/Services/Workflows/Robot/Result/UpdateRobotResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Robot/Result/WorkflowRobotsResult.php b/src/Services/Workflows/Robot/Result/WorkflowRobotsResult.php
index 95f2523a..c2145357 100644
--- a/src/Services/Workflows/Robot/Result/WorkflowRobotsResult.php
+++ b/src/Services/Workflows/Robot/Result/WorkflowRobotsResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Robot/Service/Robot.php b/src/Services/Workflows/Robot/Service/Robot.php
index 891f5ce7..be7c4f20 100644
--- a/src/Services/Workflows/Robot/Service/Robot.php
+++ b/src/Services/Workflows/Robot/Service/Robot.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Task/Result/WorkflowTaskCompleteResult.php b/src/Services/Workflows/Task/Result/WorkflowTaskCompleteResult.php
index e4d5d170..278b63cf 100644
--- a/src/Services/Workflows/Task/Result/WorkflowTaskCompleteResult.php
+++ b/src/Services/Workflows/Task/Result/WorkflowTaskCompleteResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Task/Result/WorkflowTaskItemResult.php b/src/Services/Workflows/Task/Result/WorkflowTaskItemResult.php
index 09338ed1..10ba5eca 100644
--- a/src/Services/Workflows/Task/Result/WorkflowTaskItemResult.php
+++ b/src/Services/Workflows/Task/Result/WorkflowTaskItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Task/Result/WorkflowTasksResult.php b/src/Services/Workflows/Task/Result/WorkflowTasksResult.php
index f1fd9113..e4be2947 100644
--- a/src/Services/Workflows/Task/Result/WorkflowTasksResult.php
+++ b/src/Services/Workflows/Task/Result/WorkflowTasksResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Task/Service/Batch.php b/src/Services/Workflows/Task/Service/Batch.php
index ab408b62..8a3b0d25 100644
--- a/src/Services/Workflows/Task/Service/Batch.php
+++ b/src/Services/Workflows/Task/Service/Batch.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Task/Service/Task.php b/src/Services/Workflows/Task/Service/Task.php
index ca5ee0a8..ccbb226e 100644
--- a/src/Services/Workflows/Task/Service/Task.php
+++ b/src/Services/Workflows/Task/Service/Task.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Template/Result/WorkflowTemplateItemResult.php b/src/Services/Workflows/Template/Result/WorkflowTemplateItemResult.php
index a89ea60a..2c3f3629 100644
--- a/src/Services/Workflows/Template/Result/WorkflowTemplateItemResult.php
+++ b/src/Services/Workflows/Template/Result/WorkflowTemplateItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Template/Result/WorkflowTemplatesResult.php b/src/Services/Workflows/Template/Result/WorkflowTemplatesResult.php
index 553efed2..2680c618 100644
--- a/src/Services/Workflows/Template/Result/WorkflowTemplatesResult.php
+++ b/src/Services/Workflows/Template/Result/WorkflowTemplatesResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Template/Service/Batch.php b/src/Services/Workflows/Template/Service/Batch.php
index af3aee34..830b3e46 100644
--- a/src/Services/Workflows/Template/Service/Batch.php
+++ b/src/Services/Workflows/Template/Service/Batch.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Template/Service/Template.php b/src/Services/Workflows/Template/Service/Template.php
index 44874a13..c12b9820 100644
--- a/src/Services/Workflows/Template/Service/Template.php
+++ b/src/Services/Workflows/Template/Service/Template.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Workflow/Request/IncomingWorkflowRequest.php b/src/Services/Workflows/Workflow/Request/IncomingWorkflowRequest.php
index bfde824f..06e20671 100644
--- a/src/Services/Workflows/Workflow/Request/IncomingWorkflowRequest.php
+++ b/src/Services/Workflows/Workflow/Request/IncomingWorkflowRequest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Workflow/Result/WorkflowInstanceItemResult.php b/src/Services/Workflows/Workflow/Result/WorkflowInstanceItemResult.php
index a8397d8a..942db4a9 100644
--- a/src/Services/Workflows/Workflow/Result/WorkflowInstanceItemResult.php
+++ b/src/Services/Workflows/Workflow/Result/WorkflowInstanceItemResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Workflow/Result/WorkflowInstanceStartResult.php b/src/Services/Workflows/Workflow/Result/WorkflowInstanceStartResult.php
index 2677bc9a..99c146f0 100644
--- a/src/Services/Workflows/Workflow/Result/WorkflowInstanceStartResult.php
+++ b/src/Services/Workflows/Workflow/Result/WorkflowInstanceStartResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Workflow/Result/WorkflowInstancesResult.php b/src/Services/Workflows/Workflow/Result/WorkflowInstancesResult.php
index 97be077c..45d8c647 100644
--- a/src/Services/Workflows/Workflow/Result/WorkflowInstancesResult.php
+++ b/src/Services/Workflows/Workflow/Result/WorkflowInstancesResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Workflow/Result/WorkflowKillResult.php b/src/Services/Workflows/Workflow/Result/WorkflowKillResult.php
index 4173ee57..1f71e8f5 100644
--- a/src/Services/Workflows/Workflow/Result/WorkflowKillResult.php
+++ b/src/Services/Workflows/Workflow/Result/WorkflowKillResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Workflow/Result/WorkflowTerminationResult.php b/src/Services/Workflows/Workflow/Result/WorkflowTerminationResult.php
index a9ad8f88..65405c41 100644
--- a/src/Services/Workflows/Workflow/Result/WorkflowTerminationResult.php
+++ b/src/Services/Workflows/Workflow/Result/WorkflowTerminationResult.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Workflow/Service/Batch.php b/src/Services/Workflows/Workflow/Service/Batch.php
index 653cd4f7..d8c3df6d 100644
--- a/src/Services/Workflows/Workflow/Service/Batch.php
+++ b/src/Services/Workflows/Workflow/Service/Batch.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/Workflow/Service/Workflow.php b/src/Services/Workflows/Workflow/Service/Workflow.php
index 7d938525..55071fc4 100644
--- a/src/Services/Workflows/Workflow/Service/Workflow.php
+++ b/src/Services/Workflows/Workflow/Service/Workflow.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/src/Services/Workflows/WorkflowsServiceBuilder.php b/src/Services/Workflows/WorkflowsServiceBuilder.php
index cb9d84a5..e7475a5e 100644
--- a/src/Services/Workflows/WorkflowsServiceBuilder.php
+++ b/src/Services/Workflows/WorkflowsServiceBuilder.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright and 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;
diff --git a/tests/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceTest.php b/tests/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceTest.php
index 2ee76d58..ab38daf9 100644
--- a/tests/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceTest.php
+++ b/tests/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Application/Contracts/ApplicationInstallations/Repository/ApplicationInstallationRepositoryInterfaceTest.php b/tests/Application/Contracts/ApplicationInstallations/Repository/ApplicationInstallationRepositoryInterfaceTest.php
index 614fa20c..f7024979 100644
--- a/tests/Application/Contracts/ApplicationInstallations/Repository/ApplicationInstallationRepositoryInterfaceTest.php
+++ b/tests/Application/Contracts/ApplicationInstallations/Repository/ApplicationInstallationRepositoryInterfaceTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php b/tests/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php
index 21d89660..c5c24274 100644
--- a/tests/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php
+++ b/tests/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterfaceTest.php b/tests/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterfaceTest.php
index 61a93bc3..e3fb3818 100644
--- a/tests/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterfaceTest.php
+++ b/tests/Application/Contracts/Bitrix24Accounts/Repository/Bitrix24AccountRepositoryInterfaceTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterfaceTest.php b/tests/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterfaceTest.php
index 9083b80b..140f9eb9 100644
--- a/tests/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterfaceTest.php
+++ b/tests/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterfaceTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Application/Contracts/Bitrix24Partners/Repository/Bitrix24PartnerRepositoryInterfaceTest.php b/tests/Application/Contracts/Bitrix24Partners/Repository/Bitrix24PartnerRepositoryInterfaceTest.php
index 5136247d..58f3b93e 100644
--- a/tests/Application/Contracts/Bitrix24Partners/Repository/Bitrix24PartnerRepositoryInterfaceTest.php
+++ b/tests/Application/Contracts/Bitrix24Partners/Repository/Bitrix24PartnerRepositoryInterfaceTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceTest.php b/tests/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceTest.php
index 4e28300d..dab78765 100644
--- a/tests/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceTest.php
+++ b/tests/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php b/tests/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php
index f255af7f..66ec443a 100644
--- a/tests/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php
+++ b/tests/Application/Contracts/ContactPersons/Repository/ContactPersonRepositoryInterfaceTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/ApplicationBridge/ApplicationCredentialsProvider.php b/tests/ApplicationBridge/ApplicationCredentialsProvider.php
index 00713385..0524e7fe 100644
--- a/tests/ApplicationBridge/ApplicationCredentialsProvider.php
+++ b/tests/ApplicationBridge/ApplicationCredentialsProvider.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/ApplicationBridge/AuthTokenFileStorage.php b/tests/ApplicationBridge/AuthTokenFileStorage.php
index 1af6a99e..787324de 100644
--- a/tests/ApplicationBridge/AuthTokenFileStorage.php
+++ b/tests/ApplicationBridge/AuthTokenFileStorage.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/ApplicationBridge/AuthTokenRepositoryInterface.php b/tests/ApplicationBridge/AuthTokenRepositoryInterface.php
index 8302e31b..fa1389d9 100644
--- a/tests/ApplicationBridge/AuthTokenRepositoryInterface.php
+++ b/tests/ApplicationBridge/AuthTokenRepositoryInterface.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/ApplicationBridge/index.php b/tests/ApplicationBridge/index.php
index 90947415..69093196 100644
--- a/tests/ApplicationBridge/index.php
+++ b/tests/ApplicationBridge/index.php
@@ -1,6 +1,15 @@
 
+ *
+ * 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;
diff --git a/tests/ApplicationBridge/install.php b/tests/ApplicationBridge/install.php
index eae01705..5ca9c29f 100644
--- a/tests/ApplicationBridge/install.php
+++ b/tests/ApplicationBridge/install.php
@@ -1,4 +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
index 2d7a0360..b95a5763 100644
--- a/tests/Builders/DemoDataGenerator.php
+++ b/tests/Builders/DemoDataGenerator.php
@@ -1,6 +1,15 @@
 
+ *
+ * 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;
diff --git a/tests/Builders/Services/CRM/PhoneCollectionBuilder.php b/tests/Builders/Services/CRM/PhoneCollectionBuilder.php
index 2dbe6819..71e4addd 100644
--- a/tests/Builders/Services/CRM/PhoneCollectionBuilder.php
+++ b/tests/Builders/Services/CRM/PhoneCollectionBuilder.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Builders/Services/CRM/PhoneNumberBuilder.php b/tests/Builders/Services/CRM/PhoneNumberBuilder.php
index 2efdd24d..62d3eedc 100644
--- a/tests/Builders/Services/CRM/PhoneNumberBuilder.php
+++ b/tests/Builders/Services/CRM/PhoneNumberBuilder.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/CustomAssertions/CustomBitrix24Assertions.php b/tests/CustomAssertions/CustomBitrix24Assertions.php
index 09e25ab1..5f12030d 100644
--- a/tests/CustomAssertions/CustomBitrix24Assertions.php
+++ b/tests/CustomAssertions/CustomBitrix24Assertions.php
@@ -1,6 +1,15 @@
 
+ *
+ * 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;
diff --git a/tests/Integration/Core/BatchGetTraversableTest.php b/tests/Integration/Core/BatchGetTraversableTest.php
index f21bdbf9..70f8fa20 100644
--- a/tests/Integration/Core/BatchGetTraversableTest.php
+++ b/tests/Integration/Core/BatchGetTraversableTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Core/BatchTest.php b/tests/Integration/Core/BatchTest.php
index 98dc2bcb..42c66ba0 100644
--- a/tests/Integration/Core/BatchTest.php
+++ b/tests/Integration/Core/BatchTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrderTest.php b/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrderTest.php
index c644c8a1..503c7b87 100644
--- a/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrderTest.php
+++ b/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithBatchWithoutCountOrderTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrderTest.php b/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrderTest.php
index 055313b3..7717e607 100644
--- a/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrderTest.php
+++ b/tests/Integration/Core/BulkItemsReader/ReadStrategies/FilterWithoutBatchWithoutCountOrderTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Core/CoreTest.php b/tests/Integration/Core/CoreTest.php
index 1c541897..e972f3bc 100644
--- a/tests/Integration/Core/CoreTest.php
+++ b/tests/Integration/Core/CoreTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Fabric.php b/tests/Integration/Fabric.php
index f8b635f7..238e4b9b 100644
--- a/tests/Integration/Fabric.php
+++ b/tests/Integration/Fabric.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/CRM/Activity/ReadModel/EmailFetcherTest.php b/tests/Integration/Services/CRM/Activity/ReadModel/EmailFetcherTest.php
index c8bf7ed9..b9855548 100644
--- a/tests/Integration/Services/CRM/Activity/ReadModel/EmailFetcherTest.php
+++ b/tests/Integration/Services/CRM/Activity/ReadModel/EmailFetcherTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/CRM/Activity/ReadModel/OpenLineFetcherTest.php b/tests/Integration/Services/CRM/Activity/ReadModel/OpenLineFetcherTest.php
index 10628ad5..c4ad949f 100644
--- a/tests/Integration/Services/CRM/Activity/ReadModel/OpenLineFetcherTest.php
+++ b/tests/Integration/Services/CRM/Activity/ReadModel/OpenLineFetcherTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/CRM/Activity/ReadModel/VoximplantFetcherTest.php b/tests/Integration/Services/CRM/Activity/ReadModel/VoximplantFetcherTest.php
index 6ad0af15..273739f3 100644
--- a/tests/Integration/Services/CRM/Activity/ReadModel/VoximplantFetcherTest.php
+++ b/tests/Integration/Services/CRM/Activity/ReadModel/VoximplantFetcherTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/CRM/Activity/ReadModel/WebFormFetcherTest.php b/tests/Integration/Services/CRM/Activity/ReadModel/WebFormFetcherTest.php
index f3a9b942..92bc50e7 100644
--- a/tests/Integration/Services/CRM/Activity/ReadModel/WebFormFetcherTest.php
+++ b/tests/Integration/Services/CRM/Activity/ReadModel/WebFormFetcherTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/CRM/Activity/Service/ActivityTest.php b/tests/Integration/Services/CRM/Activity/Service/ActivityTest.php
index 7bcfa784..758717ed 100644
--- a/tests/Integration/Services/CRM/Activity/Service/ActivityTest.php
+++ b/tests/Integration/Services/CRM/Activity/Service/ActivityTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/CRM/Activity/Service/BatchTest.php b/tests/Integration/Services/CRM/Activity/Service/BatchTest.php
index c7e8aadd..f2d32bd1 100644
--- a/tests/Integration/Services/CRM/Activity/Service/BatchTest.php
+++ b/tests/Integration/Services/CRM/Activity/Service/BatchTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/CRM/Contact/Service/ContactBatchTest.php b/tests/Integration/Services/CRM/Contact/Service/ContactBatchTest.php
index fafd8cb5..af252f53 100644
--- a/tests/Integration/Services/CRM/Contact/Service/ContactBatchTest.php
+++ b/tests/Integration/Services/CRM/Contact/Service/ContactBatchTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/CRM/Contact/Service/ContactTest.php b/tests/Integration/Services/CRM/Contact/Service/ContactTest.php
index 257f63f8..425fe881 100644
--- a/tests/Integration/Services/CRM/Contact/Service/ContactTest.php
+++ b/tests/Integration/Services/CRM/Contact/Service/ContactTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/CRM/Contact/Service/ContactUserfieldTest.php b/tests/Integration/Services/CRM/Contact/Service/ContactUserfieldTest.php
index 314ba302..13204f6c 100644
--- a/tests/Integration/Services/CRM/Contact/Service/ContactUserfieldTest.php
+++ b/tests/Integration/Services/CRM/Contact/Service/ContactUserfieldTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/CRM/Contact/Service/ContactUserfieldUseCaseTest.php b/tests/Integration/Services/CRM/Contact/Service/ContactUserfieldUseCaseTest.php
index 0e0cfb53..e61f7ae3 100644
--- a/tests/Integration/Services/CRM/Contact/Service/ContactUserfieldUseCaseTest.php
+++ b/tests/Integration/Services/CRM/Contact/Service/ContactUserfieldUseCaseTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/CRM/Deal/Service/BatchTest.php b/tests/Integration/Services/CRM/Deal/Service/BatchTest.php
index 08c19dbd..83aba611 100644
--- a/tests/Integration/Services/CRM/Deal/Service/BatchTest.php
+++ b/tests/Integration/Services/CRM/Deal/Service/BatchTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/CRM/Deal/Service/DealCategoryStageTest.php b/tests/Integration/Services/CRM/Deal/Service/DealCategoryStageTest.php
index 1d2066d3..cbe5aa81 100644
--- a/tests/Integration/Services/CRM/Deal/Service/DealCategoryStageTest.php
+++ b/tests/Integration/Services/CRM/Deal/Service/DealCategoryStageTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/CRM/Deal/Service/DealCategoryTest.php b/tests/Integration/Services/CRM/Deal/Service/DealCategoryTest.php
index 0507a601..1e5aea71 100644
--- a/tests/Integration/Services/CRM/Deal/Service/DealCategoryTest.php
+++ b/tests/Integration/Services/CRM/Deal/Service/DealCategoryTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/CRM/Deal/Service/DealContactTest.php b/tests/Integration/Services/CRM/Deal/Service/DealContactTest.php
index 8666e0ee..3c6da9a7 100644
--- a/tests/Integration/Services/CRM/Deal/Service/DealContactTest.php
+++ b/tests/Integration/Services/CRM/Deal/Service/DealContactTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php
index 36b64180..a5b73daa 100644
--- a/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php
+++ b/tests/Integration/Services/CRM/Deal/Service/DealProductRowsTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/CRM/Deal/Service/DealTest.php b/tests/Integration/Services/CRM/Deal/Service/DealTest.php
index 527e32a8..09fe64a8 100644
--- a/tests/Integration/Services/CRM/Deal/Service/DealTest.php
+++ b/tests/Integration/Services/CRM/Deal/Service/DealTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/CRM/Deal/Service/DealUserfieldTest.php b/tests/Integration/Services/CRM/Deal/Service/DealUserfieldTest.php
index 3055e8bc..ff46e856 100644
--- a/tests/Integration/Services/CRM/Deal/Service/DealUserfieldTest.php
+++ b/tests/Integration/Services/CRM/Deal/Service/DealUserfieldTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/CRM/Deal/Service/DealUserfieldUseCaseTest.php b/tests/Integration/Services/CRM/Deal/Service/DealUserfieldUseCaseTest.php
index 88f9d1a1..4e90aa58 100644
--- a/tests/Integration/Services/CRM/Deal/Service/DealUserfieldUseCaseTest.php
+++ b/tests/Integration/Services/CRM/Deal/Service/DealUserfieldUseCaseTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/CRM/Duplicates/Service/DuplicateTest.php b/tests/Integration/Services/CRM/Duplicates/Service/DuplicateTest.php
index d2efa86f..18282c1f 100644
--- a/tests/Integration/Services/CRM/Duplicates/Service/DuplicateTest.php
+++ b/tests/Integration/Services/CRM/Duplicates/Service/DuplicateTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/CRM/Lead/Service/BatchTest.php b/tests/Integration/Services/CRM/Lead/Service/BatchTest.php
index 8792fab2..23bfd35c 100644
--- a/tests/Integration/Services/CRM/Lead/Service/BatchTest.php
+++ b/tests/Integration/Services/CRM/Lead/Service/BatchTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/CRM/Lead/Service/LeadTest.php b/tests/Integration/Services/CRM/Lead/Service/LeadTest.php
index 9891e483..83ba1381 100644
--- a/tests/Integration/Services/CRM/Lead/Service/LeadTest.php
+++ b/tests/Integration/Services/CRM/Lead/Service/LeadTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/CRM/Products/Service/ProductsTest.php b/tests/Integration/Services/CRM/Products/Service/ProductsTest.php
index 0e9223ba..be7cd637 100644
--- a/tests/Integration/Services/CRM/Products/Service/ProductsTest.php
+++ b/tests/Integration/Services/CRM/Products/Service/ProductsTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/CRM/Userfield/Service/UserfieldTest.php b/tests/Integration/Services/CRM/Userfield/Service/UserfieldTest.php
index f1397ca5..b6391a3a 100644
--- a/tests/Integration/Services/CRM/Userfield/Service/UserfieldTest.php
+++ b/tests/Integration/Services/CRM/Userfield/Service/UserfieldTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/Catalog/Catalog/Service/CatalogTest.php b/tests/Integration/Services/Catalog/Catalog/Service/CatalogTest.php
index c20dafc9..47e03abb 100644
--- a/tests/Integration/Services/Catalog/Catalog/Service/CatalogTest.php
+++ b/tests/Integration/Services/Catalog/Catalog/Service/CatalogTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/Catalog/Product/Service/ProductTest.php b/tests/Integration/Services/Catalog/Product/Service/ProductTest.php
index 08501130..3e514c0f 100644
--- a/tests/Integration/Services/Catalog/Product/Service/ProductTest.php
+++ b/tests/Integration/Services/Catalog/Product/Service/ProductTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/IM/Service/NotifyTest.php b/tests/Integration/Services/IM/Service/NotifyTest.php
index 976c0162..a90b42e3 100644
--- a/tests/Integration/Services/IM/Service/NotifyTest.php
+++ b/tests/Integration/Services/IM/Service/NotifyTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/IMOpenLines/Service/NetworkTest.php b/tests/Integration/Services/IMOpenLines/Service/NetworkTest.php
index ee1f2e9a..9f3b564e 100644
--- a/tests/Integration/Services/IMOpenLines/Service/NetworkTest.php
+++ b/tests/Integration/Services/IMOpenLines/Service/NetworkTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/Main/Service/MainTest.php b/tests/Integration/Services/Main/Service/MainTest.php
index 7fab4e12..09100776 100644
--- a/tests/Integration/Services/Main/Service/MainTest.php
+++ b/tests/Integration/Services/Main/Service/MainTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/Placement/Service/PlacementTest.php b/tests/Integration/Services/Placement/Service/PlacementTest.php
index 1084efcc..69714442 100644
--- a/tests/Integration/Services/Placement/Service/PlacementTest.php
+++ b/tests/Integration/Services/Placement/Service/PlacementTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/Telephony/Call/Service/CallTest.php b/tests/Integration/Services/Telephony/Call/Service/CallTest.php
index 51ebcac9..e1383fca 100644
--- a/tests/Integration/Services/Telephony/Call/Service/CallTest.php
+++ b/tests/Integration/Services/Telephony/Call/Service/CallTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php b/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php
index a25f0cf7..6968f76e 100644
--- a/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php
+++ b/tests/Integration/Services/Telephony/ExternalCall/Service/ExternalCallTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php b/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php
index 113c2171..e89edda0 100644
--- a/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php
+++ b/tests/Integration/Services/Telephony/ExternalLine/Service/ExternalLineTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/Telephony/Voximplant/InfoCall/Service/InfoCallTest.php b/tests/Integration/Services/Telephony/Voximplant/InfoCall/Service/InfoCallTest.php
index 0785e5ff..dd08922e 100644
--- a/tests/Integration/Services/Telephony/Voximplant/InfoCall/Service/InfoCallTest.php
+++ b/tests/Integration/Services/Telephony/Voximplant/InfoCall/Service/InfoCallTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/Telephony/Voximplant/Line/Service/LineTest.php b/tests/Integration/Services/Telephony/Voximplant/Line/Service/LineTest.php
index 0fec82a9..d038867a 100644
--- a/tests/Integration/Services/Telephony/Voximplant/Line/Service/LineTest.php
+++ b/tests/Integration/Services/Telephony/Voximplant/Line/Service/LineTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/Telephony/Voximplant/Sip/SipTest.php b/tests/Integration/Services/Telephony/Voximplant/Sip/SipTest.php
index 2d55c0e1..ed790441 100644
--- a/tests/Integration/Services/Telephony/Voximplant/Sip/SipTest.php
+++ b/tests/Integration/Services/Telephony/Voximplant/Sip/SipTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/Telephony/Voximplant/TTS/Voices/Service/VoicesTest.php b/tests/Integration/Services/Telephony/Voximplant/TTS/Voices/Service/VoicesTest.php
index 3d0c1649..1d7a47de 100644
--- a/tests/Integration/Services/Telephony/Voximplant/TTS/Voices/Service/VoicesTest.php
+++ b/tests/Integration/Services/Telephony/Voximplant/TTS/Voices/Service/VoicesTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/Telephony/Voximplant/Url/Service/UrlTest.php b/tests/Integration/Services/Telephony/Voximplant/Url/Service/UrlTest.php
index 8f6eedb9..70271de7 100644
--- a/tests/Integration/Services/Telephony/Voximplant/Url/Service/UrlTest.php
+++ b/tests/Integration/Services/Telephony/Voximplant/Url/Service/UrlTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/Telephony/Voximplant/User/UserTest.php b/tests/Integration/Services/Telephony/Voximplant/User/UserTest.php
index 0b1f9540..2245f5cb 100644
--- a/tests/Integration/Services/Telephony/Voximplant/User/UserTest.php
+++ b/tests/Integration/Services/Telephony/Voximplant/User/UserTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/User/Service/UserTest.php b/tests/Integration/Services/User/Service/UserTest.php
index 8e9931fe..ea98df75 100644
--- a/tests/Integration/Services/User/Service/UserTest.php
+++ b/tests/Integration/Services/User/Service/UserTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/UserConsent/Service/UserConsentAgreementTest.php b/tests/Integration/Services/UserConsent/Service/UserConsentAgreementTest.php
index 76e8ff54..bb4c93dd 100644
--- a/tests/Integration/Services/UserConsent/Service/UserConsentAgreementTest.php
+++ b/tests/Integration/Services/UserConsent/Service/UserConsentAgreementTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Integration/Services/UserConsent/Service/UserConsentTest.php b/tests/Integration/Services/UserConsent/Service/UserConsentTest.php
index 7f2c25c8..e52cf207 100644
--- a/tests/Integration/Services/UserConsent/Service/UserConsentTest.php
+++ b/tests/Integration/Services/UserConsent/Service/UserConsentTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Temp/OperatingTimingTest.php b/tests/Temp/OperatingTimingTest.php
index 50ffbb87..35f48267 100644
--- a/tests/Temp/OperatingTimingTest.php
+++ b/tests/Temp/OperatingTimingTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
@@ -27,12 +36,12 @@ class OperatingTimingTest extends TestCase
      */
     public function testOperatingTiming(): void
     {
-        // С версии модуля Rest 22.0.0 в облачной версии Битрикс24 во всех ответах rest запросов в массиве time с
-        // дополнительной информацией о времени выполнения запроса добавлен дополнительный ключ operating, который
-        // говорит о времени выполнения запроса к методу конкретным приложением. Данные о времени выполнения запросов к
-        // методу суммируются. При превышении времени выполнения запросов сверх 480 секунд в рамках прошедших 10 минут
-        // данный метод блокируется для приложения. При этом все остальные методы продолжают работать.
-        // Ключ operating_reset_at возвращает timestamp в которое будет высвобождена часть лимита на данный метод.
+        // 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
@@ -46,9 +55,9 @@ public function testOperatingTiming(): void
 //        $contactsToUpdate = $this->getContactsUpdateCommand(15000);
 //
 //
-//        //todo считать количество контактов для обновления и считать количество контактов которые обновили, если не совпало, то падаем с ошибкой
-//
-//        // обновляем контакты в батч-режиме
+// //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++;
@@ -71,11 +80,9 @@ public function testOperatingTiming(): void
 //            sprintf('updated contacts count %s not equal to expected %s cmd items', $cnt, count($contactsToUpdate))
 //        );
 
-        // шаг 1 - выброс корректного исключения, что мол упали из за блокировки метода
-        // проблемы: - можно потерять часть данных при обновлении, т.к. мы не знаем, какие контакты в клиентском коде обновились, а какие нет или знаем?
-
-// todo уточнение, по возможности возвращать в исключении остаток данных, которые не успели обновиться
-
+        // 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":
 //{
@@ -110,10 +117,9 @@ public function testOperatingTiming(): void
 //[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"}
 
 
-        // шаг 2 - сделать отдельные стратегии с логикой для батча и придумать, как может быть
-        // - 2.1 ожидание разблокировки метода без завершения работы батча, т.е. скрипт будет висеть 10 минут, потом попробует продолжить работу, такое можно делать толкьо осознавая последсвия
-        // - 2.2 выброс события \ вызов обработчика за N секунд до блокировки метода, т.е делегируем логику обработки в клиентский код
-
+        // 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
 
     }
 
diff --git a/tests/Unit/Application/ApplicationStatusTest.php b/tests/Unit/Application/ApplicationStatusTest.php
index 857f7f00..b83a60e9 100644
--- a/tests/Unit/Application/ApplicationStatusTest.php
+++ b/tests/Unit/Application/ApplicationStatusTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceReferenceImplementationTest.php b/tests/Unit/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceReferenceImplementationTest.php
index e7f8a3d4..044ae6ee 100644
--- a/tests/Unit/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceReferenceImplementationTest.php
+++ b/tests/Unit/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationInterfaceReferenceImplementationTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationReferenceEntityImplementation.php b/tests/Unit/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationReferenceEntityImplementation.php
index 3bb4165e..9245e287 100644
--- a/tests/Unit/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationReferenceEntityImplementation.php
+++ b/tests/Unit/Application/Contracts/ApplicationInstallations/Entity/ApplicationInstallationReferenceEntityImplementation.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementation.php b/tests/Unit/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementation.php
index c8308294..112fa944 100644
--- a/tests/Unit/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementation.php
+++ b/tests/Unit/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementation.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementationTest.php b/tests/Unit/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementationTest.php
index be5849a3..45a8bd8d 100644
--- a/tests/Unit/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementationTest.php
+++ b/tests/Unit/Application/Contracts/ApplicationInstallations/Repository/InMemoryApplicationInstallationRepositoryImplementationTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceReferenceImplementationTest.php b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceReferenceImplementationTest.php
index d2135df7..a6fa96be 100644
--- a/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceReferenceImplementationTest.php
+++ b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountInterfaceReferenceImplementationTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountReferenceEntityImplementation.php b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountReferenceEntityImplementation.php
index 84afef59..e441c11d 100644
--- a/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountReferenceEntityImplementation.php
+++ b/tests/Unit/Application/Contracts/Bitrix24Accounts/Entity/Bitrix24AccountReferenceEntityImplementation.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementation.php b/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementation.php
index eb790fa0..b8a3ab66 100644
--- a/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementation.php
+++ b/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementation.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementationTest.php b/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementationTest.php
index 42ae95b9..689a6a54 100644
--- a/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementationTest.php
+++ b/tests/Unit/Application/Contracts/Bitrix24Accounts/Repository/InMemoryBitrix24AccountRepositoryImplementationTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterfaceReferenceImplementationTest.php b/tests/Unit/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterfaceReferenceImplementationTest.php
index 03fc12f0..ff52fb38 100644
--- a/tests/Unit/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterfaceReferenceImplementationTest.php
+++ b/tests/Unit/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerInterfaceReferenceImplementationTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerReferenceEntityImplementation.php b/tests/Unit/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerReferenceEntityImplementation.php
index 7bc6e4fe..4684f69d 100644
--- a/tests/Unit/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerReferenceEntityImplementation.php
+++ b/tests/Unit/Application/Contracts/Bitrix24Partners/Entity/Bitrix24PartnerReferenceEntityImplementation.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Application/Contracts/Bitrix24Partners/Repository/InMemoryBitrix24PartnerRepositoryImplementation.php b/tests/Unit/Application/Contracts/Bitrix24Partners/Repository/InMemoryBitrix24PartnerRepositoryImplementation.php
index bd5133c2..ca6fc91f 100644
--- a/tests/Unit/Application/Contracts/Bitrix24Partners/Repository/InMemoryBitrix24PartnerRepositoryImplementation.php
+++ b/tests/Unit/Application/Contracts/Bitrix24Partners/Repository/InMemoryBitrix24PartnerRepositoryImplementation.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Application/Contracts/Bitrix24Partners/Repository/InMemoryBitrix24PartnerRepositoryImplementationTest.php b/tests/Unit/Application/Contracts/Bitrix24Partners/Repository/InMemoryBitrix24PartnerRepositoryImplementationTest.php
index a3d822ea..29536918 100644
--- a/tests/Unit/Application/Contracts/Bitrix24Partners/Repository/InMemoryBitrix24PartnerRepositoryImplementationTest.php
+++ b/tests/Unit/Application/Contracts/Bitrix24Partners/Repository/InMemoryBitrix24PartnerRepositoryImplementationTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceReferenceImplementationTest.php b/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceReferenceImplementationTest.php
index 3f3f70d0..58032148 100644
--- a/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceReferenceImplementationTest.php
+++ b/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonInterfaceReferenceImplementationTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonReferenceEntityImplementation.php b/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonReferenceEntityImplementation.php
index 411efed6..2a72c5ac 100644
--- a/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonReferenceEntityImplementation.php
+++ b/tests/Unit/Application/Contracts/ContactPersons/Entity/ContactPersonReferenceEntityImplementation.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementation.php b/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementation.php
index 7da6f27e..6d710b7a 100644
--- a/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementation.php
+++ b/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementation.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementationTest.php b/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementationTest.php
index f0bd3836..3c4ed448 100644
--- a/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementationTest.php
+++ b/tests/Unit/Application/Contracts/ContactPersons/Repository/InMemoryContactPersonRepositoryImplementationTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Core/ApiLevelErrorHandlerTest.php b/tests/Unit/Core/ApiLevelErrorHandlerTest.php
index b49b8ba4..63c5b20e 100644
--- a/tests/Unit/Core/ApiLevelErrorHandlerTest.php
+++ b/tests/Unit/Core/ApiLevelErrorHandlerTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Core/CoreBuilderTest.php b/tests/Unit/Core/CoreBuilderTest.php
index 19ba5b02..c7926e5e 100644
--- a/tests/Unit/Core/CoreBuilderTest.php
+++ b/tests/Unit/Core/CoreBuilderTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Core/Credentials/ApplicationProfileTest.php b/tests/Unit/Core/Credentials/ApplicationProfileTest.php
index 637c3588..823ef7fa 100644
--- a/tests/Unit/Core/Credentials/ApplicationProfileTest.php
+++ b/tests/Unit/Core/Credentials/ApplicationProfileTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Core/Credentials/CredentialsTest.php b/tests/Unit/Core/Credentials/CredentialsTest.php
index c81a7de0..5085fa59 100644
--- a/tests/Unit/Core/Credentials/CredentialsTest.php
+++ b/tests/Unit/Core/Credentials/CredentialsTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Core/Credentials/ScopeTest.php b/tests/Unit/Core/Credentials/ScopeTest.php
index ab789cea..96cbdb9a 100644
--- a/tests/Unit/Core/Credentials/ScopeTest.php
+++ b/tests/Unit/Core/Credentials/ScopeTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Core/Credentials/WebhookUrlTest.php b/tests/Unit/Core/Credentials/WebhookUrlTest.php
index 318abec6..0342277c 100644
--- a/tests/Unit/Core/Credentials/WebhookUrlTest.php
+++ b/tests/Unit/Core/Credentials/WebhookUrlTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Core/Response/DTO/TimeTest.php b/tests/Unit/Core/Response/DTO/TimeTest.php
index fd98be0b..fee29aef 100644
--- a/tests/Unit/Core/Response/DTO/TimeTest.php
+++ b/tests/Unit/Core/Response/DTO/TimeTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Core/Result/AbstractItemTest.php b/tests/Unit/Core/Result/AbstractItemTest.php
index 6d9608de..6468cb85 100644
--- a/tests/Unit/Core/Result/AbstractItemTest.php
+++ b/tests/Unit/Core/Result/AbstractItemTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Infrastructure/HttpClient/RequestId/DefaultRequestIdGeneratorTest.php b/tests/Unit/Infrastructure/HttpClient/RequestId/DefaultRequestIdGeneratorTest.php
index 8da0bb9d..6946ec71 100644
--- a/tests/Unit/Infrastructure/HttpClient/RequestId/DefaultRequestIdGeneratorTest.php
+++ b/tests/Unit/Infrastructure/HttpClient/RequestId/DefaultRequestIdGeneratorTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Services/CRM/CRMServiceBuilderTest.php b/tests/Unit/Services/CRM/CRMServiceBuilderTest.php
index 91a29bca..e7819d61 100644
--- a/tests/Unit/Services/CRM/CRMServiceBuilderTest.php
+++ b/tests/Unit/Services/CRM/CRMServiceBuilderTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Services/IM/IMServiceBuilderTest.php b/tests/Unit/Services/IM/IMServiceBuilderTest.php
index d151d96a..7124e058 100644
--- a/tests/Unit/Services/IM/IMServiceBuilderTest.php
+++ b/tests/Unit/Services/IM/IMServiceBuilderTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Services/Main/MainServiceBuilderTest.php b/tests/Unit/Services/Main/MainServiceBuilderTest.php
index 255207b5..eb6487e4 100644
--- a/tests/Unit/Services/Main/MainServiceBuilderTest.php
+++ b/tests/Unit/Services/Main/MainServiceBuilderTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Services/ServiceBuilderTest.php b/tests/Unit/Services/ServiceBuilderTest.php
index f50cfb00..698e1ec4 100644
--- a/tests/Unit/Services/ServiceBuilderTest.php
+++ b/tests/Unit/Services/ServiceBuilderTest.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Stubs/NullBatch.php b/tests/Unit/Stubs/NullBatch.php
index d3109e8c..8b28d0c8 100644
--- a/tests/Unit/Stubs/NullBatch.php
+++ b/tests/Unit/Stubs/NullBatch.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Stubs/NullBulkItemsReader.php b/tests/Unit/Stubs/NullBulkItemsReader.php
index 9f2b8500..5548be03 100644
--- a/tests/Unit/Stubs/NullBulkItemsReader.php
+++ b/tests/Unit/Stubs/NullBulkItemsReader.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/Unit/Stubs/NullCore.php b/tests/Unit/Stubs/NullCore.php
index eadfa259..2e359926 100644
--- a/tests/Unit/Stubs/NullCore.php
+++ b/tests/Unit/Stubs/NullCore.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
index ba8c63ba..aad20729 100644
--- a/tests/bootstrap.php
+++ b/tests/bootstrap.php
@@ -1,5 +1,14 @@
 
+ *
+ * For 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 Symfony\Component\Console\Input\ArgvInput;
diff --git a/tools/Commands/CopyPropertyValues.php b/tools/Commands/CopyPropertyValues.php
index d4cd9d8c..4c2bfd1c 100644
--- a/tools/Commands/CopyPropertyValues.php
+++ b/tools/Commands/CopyPropertyValues.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tools/Commands/GenerateContactsCommand.php b/tools/Commands/GenerateContactsCommand.php
index 26880314..0c77721c 100644
--- a/tools/Commands/GenerateContactsCommand.php
+++ b/tools/Commands/GenerateContactsCommand.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
@@ -157,7 +166,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
                 );
             }
             $timeEnd = microtime(true);
-            $io->writeln(GenerateContactsCommand . phpsprintf('batch query duration: %s seconds', round($timeEnd - $timeStart, 2)) . PHP_EOL . PHP_EOL);
+            $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);
diff --git a/tools/Commands/PerformanceBenchmarks/ListCommand.php b/tools/Commands/PerformanceBenchmarks/ListCommand.php
index 31b8e1d4..7a2a70d2 100644
--- a/tools/Commands/PerformanceBenchmarks/ListCommand.php
+++ b/tools/Commands/PerformanceBenchmarks/ListCommand.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;
diff --git a/tools/Commands/ShowFieldsDescriptionCommand.php b/tools/Commands/ShowFieldsDescriptionCommand.php
index c24d8733..d13cee95 100644
--- a/tools/Commands/ShowFieldsDescriptionCommand.php
+++ b/tools/Commands/ShowFieldsDescriptionCommand.php
@@ -1,5 +1,14 @@
 
+ *
+ * For the full copyright 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;

From 0744b27a30b7363df81f69a365242e3e11f7a30a Mon Sep 17 00:00:00 2001
From: mesilov 
Date: Wed, 28 Aug 2024 01:43:19 +0600
Subject: [PATCH 134/138] Update CHANGELOG for version 2.0 release

Add new section documenting the release of version 2.0 with an updated SDK version. This provides a consistent version history for users.

Signed-off-by: mesilov 
---
 CHANGELOG.md | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0f69316b..0c9a7ca9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,8 @@
 # bitrix24-php-sdk change log
 
+## 2.0 — 28.08.2024
+* bump sdk version
+
 ## 2.0-beta.3 — 15.08.2024
 
 ### Added

From 47b4071b253a08f454f1e716c45b9ca0605cc2e4 Mon Sep 17 00:00:00 2001
From: mesilov 
Date: Wed, 28 Aug 2024 01:45:51 +0600
Subject: [PATCH 135/138] Update testing commands and linting instructions

Streamlined the test running instructions and corrected linting commands in the CONTRIBUTING.md. Fixed a typo in the coding standards section and ensured consistent capitalization for GitHub references.

Signed-off-by: mesilov 
---
 CONTRIBUTING.md | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 14eb68a4..2a796ee0 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -5,10 +5,7 @@
 1.  Fork the repo
 2.  Clone the repo to local
 3.  Install dependencies: `composer update` (this assumes you have 'composer' aliased to wherever your composer.phar lives)
-4.  Run the tests. We only take pull requests with passing tests, and it's great to know that you have a clean slate:
-    `composer phpstan-analyse`
-    `composer phpunit-run-unit-tests`
-    `composer phpunit-run-integration-tests`
+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
 
@@ -19,10 +16,12 @@ New features that does not have any BC Breaks are going to be added in next mino
 
 ## Codding standards
 
-In order to fix codding standards please exeecute: 
+In order to fix codding standards please execute: 
 
 ```shell
-composer phpstan-analyse
+make lint-phpstan
+make lint-rector
+make lint-rector-fix
 ```
 
 ## Patches and bugfixes 
@@ -36,4 +35,4 @@ composer phpstan-analyse
 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
+4.  Create Pull Request on GitHub to against proper branch

From 02c1b0153bcf6e382c9cddb5c53eae70593ebdf6 Mon Sep 17 00:00:00 2001
From: mesilov 
Date: Wed, 28 Aug 2024 02:04:06 +0600
Subject: [PATCH 136/138] Update Bitrix24 PHP SDK documentation links

Corrected the view links for various API methods in the Bitrix24 PHP SDK documentation. Ensured that each method now links to the appropriate section on Bitrix24's REST API documentation site.

Signed-off-by: mesilov 
---
 docs/EN/Services/bitrix24-php-sdk-methods.md | 320 +++++++++----------
 1 file changed, 160 insertions(+), 160 deletions(-)

diff --git a/docs/EN/Services/bitrix24-php-sdk-methods.md b/docs/EN/Services/bitrix24-php-sdk-methods.md
index 1ce25734..4f91a451 100644
--- a/docs/EN/Services/bitrix24-php-sdk-methods.md
+++ b/docs/EN/Services/bitrix24-php-sdk-methods.md
@@ -2,163 +2,163 @@
 
 | **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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L44-L47)
Return type
[`Bitrix24\SDK\Services\Main\Result\ServerTimeResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L61-L64)
Return type
[`Bitrix24\SDK\Services\Main\Result\UserProfileResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L79-L84)
Return type
[`Bitrix24\SDK\Core\Response\Response`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L99-L104)
Return type
[`Bitrix24\SDK\Core\Response\Response`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L119-L126)
Return type
[`Bitrix24\SDK\Services\Main\Result\MethodAffordabilityResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L157-L160)
Return type
[`Bitrix24\SDK\Core\Response\Response`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L212-L215)
Return type
[`Bitrix24\SDK\Core\Response\Response`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L229-L232)
Return type
[`Bitrix24\SDK\Services\Main\Result\ApplicationInfoResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Main.php#L246-L249)
Return type
[`Bitrix24\SDK\Services\Main\Result\IsUserAdminResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Catalog/Service/Catalog.php#L81-L84)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Product/Service/Product.php#L92-L95)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Catalog/Product/Service/Product.php#L131-L142)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Userfield/Service/Userfield.php#L77-L80)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategory.php#L55-L65)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategory.php#L83-L93)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategory.php#L109-L112)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategory.php#L150-L153)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealCategory.php#L269-L280)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/Deal.php#L105-L116)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/Deal.php#L134-L144)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/Deal.php#L277-L289)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealProductRows.php#L108-L119)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealUserfield.php#L139-L159)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealUserfield.php#L177-L187)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealUserfield.php#L232-L243)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealContact.php#L49-L64)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealContact.php#L78-L81)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealContact.php#L127-L137)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealContact.php#L160-L171)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Deal/Service/DealContact.php#L190-L203)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/Contact.php#L117-L128)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/Contact.php#L146-L156)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/Contact.php#L172-L175)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/Contact.php#L401-L413)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/ContactUserfield.php#L137-L157)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/ContactUserfield.php#L175-L185)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Contact/Service/ContactUserfield.php#L230-L241)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L110-L120)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L138-L148)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L164-L167)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Activity/Service/Activity.php#L382-L393)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Product/Service/Product.php#L87-L97)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Product/Service/Product.php#L115-L125)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Product/Service/Product.php#L162-L165)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Product/Service/Product.php#L240-L251)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Lead/Service/Lead.php#L124-L135)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Lead/Service/Lead.php#L153-L163)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Lead/Service/Lead.php#L179-L182)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Lead/Service/Lead.php#L316-L328)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Item/Service/Item.php#L88-L95)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Item/Service/Item.php#L112-L115)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/CRM/Item/Service/Item.php#L177-L189)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Activity/Service/Activity.php#L147-L153)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Template/Service/Template.php#L57-L72)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Template/Service/Template.php#L92-L127)
Return type
[``](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/)| -|`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/feature/390-prepare-publish-2-0/src/Services/Workflows/Template/Service/Template.php#L145-L150)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Workflows/Robot/Service/Robot.php#L110-L116)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/User/Service/User.php#L43-L46)
Return type
[`Bitrix24\SDK\Core\Result\FieldsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/User/Service/User.php#L59-L62)
Return type
[`Bitrix24\SDK\Services\User\Result\UserResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/User/Service/User.php#L77-L92)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/User/Service/User.php#L104-L116)
Return type
[`Bitrix24\SDK\Services\User\Result\UsersResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/User/Service/User.php#L129-L137)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/User/Service/User.php#L151-L154)
Return type
[`Bitrix24\SDK\Services\User\Result\UsersResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/ExternalCall/Service/ExternalCall.php#L324-L331)
Return type
[`Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/ExternalCall/Service/ExternalCall.php#L347-L354)
Return type
[`Bitrix24\SDK\Core\Result\UserInterfaceDialogCallResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Telephony/ExternalLine/Service/ExternalLine.php#L76-L81)
Return type
[`Bitrix24\SDK\Core\Result\EmptyResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IM/Notify/Service/Notify.php#L44-L64)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IM/Notify/Service/Notify.php#L71-L91)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IM/Notify/Service/Notify.php#L98-L112)
Return type
[`Bitrix24\SDK\Core\Result\DeletedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IM/Notify/Service/Notify.php#L156-L167)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IM/Notify/Service/Notify.php#L174-L186)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IM/Notify/Service/Notify.php#L193-L205)
Return type
[`Bitrix24\SDK\Core\Result\UpdatedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/UserConsent/Service/UserConsent.php#L40-L43)
Return type
[`Bitrix24\SDK\Core\Result\AddedItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/UserConsent/Service/UserConsentAgreement.php#L39-L42)
Return type
[`Bitrix24\SDK\Services\UserConsent\Result\UserConsentAgreementsResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/UserConsent/Service/UserConsentAgreement.php#L54-L70)
Return type
[`Bitrix24\SDK\Services\UserConsent\Result\UserConsentAgreementTextResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IMOpenLines/Service/Network.php#L38-L48)
Return type
[`Bitrix24\SDK\Services\IMOpenLines\Result\JoinOpenLineResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/IMOpenLines/Service/Network.php#L58-L80)
Return type
[`Bitrix24\SDK\Services\IMOpenLines\Result\AddedMessageItemResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Event.php#L46-L54)
Return type
[`Bitrix24\SDK\Services\Main\Result\EventListResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Event.php#L69-L85)
Return type
[`Bitrix24\SDK\Services\Main\Result\EventHandlerBindResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Event.php#L100-L112)
Return type
[`Bitrix24\SDK\Services\Main\Result\EventHandlerUnbindResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Event.php#L125-L128)
Return type
[`Bitrix24\SDK\Core\Response\Response`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Main/Service/Event.php#L142-L145)
Return type
[`Bitrix24\SDK\Services\Main\Result\EventHandlersResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/UserFieldType.php#L45-L58)
Return type
[`Bitrix24\SDK\Services\Placement\Result\RegisterUserTypeResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/UserFieldType.php#L72-L77)
Return type
[`Bitrix24\SDK\Services\Placement\Result\UserFieldTypesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/UserFieldType.php#L96-L109)
Return type
[`Bitrix24\SDK\Services\Placement\Result\RegisterUserTypeResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/UserFieldType.php#L125-L135)
Return type
[`Bitrix24\SDK\Services\Placement\Result\DeleteUserTypeResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/Placement.php#L42-L54)
Return type
[`Bitrix24\SDK\Services\Placement\Result\PlacementBindResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/Placement.php#L68-L79)
Return type
[`Bitrix24\SDK\Services\Placement\Result\PlacementUnbindResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/Placement.php#L93-L100)
Return type
[`Bitrix24\SDK\Services\Placement\Result\PlacementLocationCodesResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/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/feature/390-prepare-publish-2-0/src/Services/Placement/Service/Placement.php#L114-L117)
Return type
[`Bitrix24\SDK\Services\Placement\Result\PlacementsLocationInformationResult`](https://github.com/mesilov/bitrix24-php-sdk/blob/feature/390-prepare-publish-2-0/src/Services/Placement/Result/PlacementsLocationInformationResult.php)| \ No newline at end of file +|`–`|[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 From 5904124c0fe8e0fce82d829389be0452881fcfb1 Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 28 Aug 2024 02:11:16 +0600 Subject: [PATCH 137/138] Remove redundant text from Sponsors section Eliminated "Help bitrix24-php-sdk by" to streamline the Sponsors section. This change improves readability and ensures the call-to-action is more direct. Signed-off-by: mesilov --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 920713ba..f41e1b1a 100644 --- a/README.md +++ b/README.md @@ -345,7 +345,7 @@ in this project. ## Sponsors -Help bitrix24-php-sdk by [boosty.to/bitrix24-php-sdk](https://boosty.to/bitrix24-php-sdk) +[boosty.to/bitrix24-php-sdk](https://boosty.to/bitrix24-php-sdk) ## Need custom Bitrix24 application? From 5703ff60a92e98e98be0cc4244b2a529d86057b4 Mon Sep 17 00:00:00 2001 From: mesilov Date: Wed, 28 Aug 2024 23:52:27 +0600 Subject: [PATCH 138/138] Update EventDispatcherInterface import to use Symfony Contracts This change modifies the import of EventDispatcherInterface to use the Symfony Contracts package instead of the Symfony Component package. This enhances code compatibility and aligns with modern Symfony best practices. Signed-off-by: mesilov --- src/Services/ServiceBuilderFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Services/ServiceBuilderFactory.php b/src/Services/ServiceBuilderFactory.php index dc44bac5..c7af145f 100644 --- a/src/Services/ServiceBuilderFactory.php +++ b/src/Services/ServiceBuilderFactory.php @@ -23,7 +23,7 @@ use Bitrix24\SDK\Core\Credentials\WebhookUrl; use Bitrix24\SDK\Core\Exceptions\InvalidArgumentException; use Psr\Log\LoggerInterface; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class ServiceBuilderFactory {